Bootstrap Modal In ASP.NET MVC With CRUD Operations
Good afternoon fellow developers!
I have been working with Bootstrap Modals before and it's time to demonstrate its significance using a simple ASP.NET MVC CRUD (Create Update Delete) application project using Entity Framework Database First approach. First is to create a basic BookDetails table on your SQL Server instance.
Next is to create an ASP.NET MVC project and add references to jQuery and Bootstrap Scripts + CSS. Then establish a connection between the created table and your project by adding an Entity Framework. In my situation, I named it as BooksEntities. Once a connection has been created, you already have a model class defined by the Entity Framework called BookDetails. The connection string generated by the Entity Framework is shown below.
In your Layout.cshtml page, make sure to reference the jQuery and Bootstrap scripts since these will be used by the modals.
In your models folder, add a class for paging records. This will be used by the view later.
Create a view model class inside the Models folder that contains a property for the BookDetail class that is used by the controller and partial views for model binding.
Create a view for the Index that has a table that shows the records from the database with the ability to create, update and delete those records. The view uses WebGrid Class from System.Web.Helpers namespace to display those information in a tabular manner. You may use other types of front-end tables to show data since the emphasis of this tutorial is how to use the Bootstrap Modal. Below is the main view that contains the code of the table and modal placeholders for Create, Update, Delete and Show Details.
Create an external JavaScript file called BookDetail.js that contains the functions to open the Bootstrap modals.
In your controller class, add the codes to create, update, delete and show information from the database.
Finally, add partial views for the CRUD operations since these views are the content of the Bootstrap Modals.
Create Modal - AddBookDetails.cshtml.
Update Modal - EditBookDetails.cshtml.
Delete Modal - DeleteBookDetails.cshtml.
Details Modal - BookDetails.cshtml.
Output
I have been working with Bootstrap Modals before and it's time to demonstrate its significance using a simple ASP.NET MVC CRUD (Create Update Delete) application project using Entity Framework Database First approach. First is to create a basic BookDetails table on your SQL Server instance.
USE [DemoDB] GO /****** Object: Table [dbo].[BookDetails] Script Date: 11/2/2020 12:26:53 PM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[BookDetails]( [BookSerialNo] [int] IDENTITY(1,1) NOT NULL, [BookISBN] [nchar](15) NULL, [BookTitle] [varchar](120) NULL, [BookAuthor] [varchar](60) NULL, [BookPublisher] [varchar](50) NULL, [BookCategory] [varchar](20) NULL, PRIMARY KEY CLUSTERED ( [BookSerialNo] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
<connectionStrings> <add name="BooksEntities" connectionString="metadata=res://*/Models.BooksEntities.csdl|res://*/Models.BooksEntities.ssdl|res://*/Models.BooksEntities.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=DemoDB;Integrated Security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /> </connectionStrings>
@Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") <script type="text/javascript" src="~/Scripts/BookDetail.js"></script>
using System; using System.Collections.Generic; namespace BootstrapDemo.Models { public class PagedList<T> { public List<T> Content { get; set; } public Int32 CurrentPage { get; set; } public Int32 PageSize { get; set; } public int TotalRecords { get; set; } public int TotalPages { get { return (int)Math.Ceiling((decimal)TotalRecords / PageSize); } } } }
public class BooksViewModel { public BookDetail BookDetail { get; set; } }
@{ ViewBag.Title = "Home Page"; } @using BootstrapDemo.Models @model BootstrapDemo.Models.PagedList<BookDetail> <script type="text/javascript" src="~/Scripts/jquery-1.10.2.js"></script> <br /> <div> <a class="btn btn-success" data-modal="" id="btnCreate" onclick="OpenAddModal()"> <span class="glyphicon glyphicon-plus"></span> </a> </div> <div style="margin-top:17px;"> @{ var grid = new WebGrid( canPage: true, rowsPerPage: Model.PageSize, canSort: false, ajaxUpdateContainerId: "grid"); grid.Bind(Model.Content, rowCount: Model.TotalRecords, autoSortAndPage: false); grid.Pager(mode: WebGridPagerModes.All); @grid.Table(htmlAttributes: new { id = "grid" }, fillEmptyRows: false, tableStyle: "table table-stripped table-hover", columns: grid.Columns( grid.Column("BookSerialNo", "Serial No."), grid.Column("BookISBN", "ISBN"), grid.Column("BookTitle", "Title"), grid.Column("BookAuthor", "Author"), grid.Column("BookPublisher", "Publisher"), grid.Column("BookCategory", "Category"), grid.Column(header: "Action", canSort: false, style: "action", format: @<text> @Html.Raw("<a id='ViewEdit' data-modal='' onclick='OpenEditModal(" + item.BookSerialNo + ")' title='Edit'> <span class='glyphicon glyphicon-edit'> </span> </a>") @Html.Raw("<a id='ViewDelete' data-modal='' onclick='OpenDeleteModal(" + item.BookSerialNo + ")' title='Delete'> <span class='glyphicon glyphicon-trash'> </span> </a>") @Html.Raw("<a id='ViewDetail' data-modal='' onclick='OpenDetailsModal(" + item.BookSerialNo + ")' title='Details'> <span class='glyphicon glyphicon-search'> </span> </a>") </text>) )); <div style="text-align:right;margin-top:-30px;"> @grid.PagerList(mode: WebGridPagerModes.All, paginationStyle: "pagination pagination-sm pagination-right") </div> } </div> <!-- modal placeholders--> <div id="modal-edit" class="modal fade"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div id='modal-edit-content'></div> </div> </div> </div> <div id="modal-add" class=" modal fade in"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div id='modal-add-content'></div> </div> </div> </div> <div id="modal-delete" class=" modal fade in"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div id='modal-delete-content'></div> </div> </div> </div> <div id="modal-details" class="modal fade in"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div id='modal-details-content'></div> </div> </div> </div>
function OpenEditModal(id) { var data = { serialNumber: id }; $.ajax( { type: 'GET', url: '/Home/Edit', contentType: 'application/json; charset=utf=8', data: data, success: function (result) { $('#modal-edit-content').html(result); $('#modal-edit').modal('show'); }, error: function (er) { alert(er); } }); } function OpenDeleteModal(id) { var data = { serialNumber: id }; $.ajax( { type: 'GET', url: '/Home/Delete', contentType: 'application/json; charset=utf=8', data: data, success: function (result) { $('#modal-delete-content').html(result); $('#modal-delete').modal('show'); }, error: function (er) { alert(er); } }); } function OpenDetailsModal(id) { var data = { serialNumber: id }; $.ajax( { type: 'GET', url: '/Home/Details', contentType: 'application/json; charset=utf=8', data: data, success: function (result) { $('#modal-details-content').html(result); $('#modal-details').modal('show'); }, error: function (er) { alert(er); } }); } function OpenAddModal() { $.ajax( { type: 'GET', url: '/Home/Create', contentType: 'application/json; charset=utf=8', success: function (result) { $('#modal-add-content').html(result); $('#modal-add').modal('show'); }, error: function (er) { alert(er); } }); }
using BootstrapDemo.Models; using System.Data.Entity; using System.Linq; using System.Web.Mvc; namespace BootstrapDemo.Controllers { public class HomeController : Controller { private BooksEntities db; public ActionResult Index(int page = 1, int pageSize = 10) { var model = new PagedList<BookDetail>(); using (db = new BooksEntities()) { model.Content = db.BookDetails .OrderBy(p => p.BookSerialNo) .Skip((page - 1) * pageSize) .Take(pageSize) .ToList(); model.TotalRecords = db.BookDetails.ToList().Count; } model.CurrentPage = page; model.PageSize = pageSize; return View(model); } [HttpGet] public PartialViewResult Create() { return PartialView("AddBookDetails"); } [HttpPost] public ActionResult Create(BooksViewModel model) { using (db = new BooksEntities()) { if (model != null) { db.BookDetails.Add(model.BookDetail); db.SaveChanges(); } } return RedirectToAction("Index"); } [HttpGet] public PartialViewResult Edit(int? serialNumber) { var model = new BooksViewModel(); using (db = new BooksEntities()) { model.BookDetail = (from item in db.BookDetails where item.BookSerialNo == serialNumber select item).FirstOrDefault(); } return PartialView("EditBookDetails", model); } [HttpPost] public ActionResult Edit(BooksViewModel model) { using (db = new BooksEntities()) { var record = db.BookDetails.Where(t => t.BookSerialNo == model.BookDetail.BookSerialNo); if (record != null) { db.Entry(model.BookDetail).State = EntityState.Modified; db.SaveChanges(); } } return RedirectToAction("Index"); } [HttpGet] public PartialViewResult Delete(int? serialNumber) { var model = new BooksViewModel(); using (db = new BooksEntities()) { model.BookDetail = (from item in db.BookDetails where item.BookSerialNo == serialNumber select item).FirstOrDefault(); } return PartialView("DeleteBookDetails", model); } [HttpPost] public ActionResult Delete(BooksViewModel model) { using (db = new BooksEntities()) { if (model != null) { var obj = db.BookDetails.Find(model.BookDetail.BookSerialNo); db.BookDetails.Remove(obj); db.SaveChanges(); } } return RedirectToAction("Index"); } [HttpGet] public PartialViewResult Details(int? serialNumber) { var model = new BooksViewModel(); using (db = new BooksEntities()) { model.BookDetail = (from item in db.BookDetails where item.BookSerialNo == serialNumber select item).FirstOrDefault(); } return PartialView("BookDetails", model); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
Create Modal - AddBookDetails.cshtml.
@model BootstrapDemo.Models.BooksViewModel <link rel="stylesheet" href="~/Content/bootstrap.min.css" /> <script type="text/javascript" src="~/Scripts/bootstrap.min.js"></script> @using (Html.BeginForm("Create", "Home", FormMethod.Post)) { @Html.AntiForgeryToken() <h3 class="modal-title">Add New Item</h3> <hr /> @Html.ValidationSummary(true) <div class="modal-body"> @Html.LabelFor(model => model.BookDetail.BookISBN, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookISBN, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookISBN) @Html.LabelFor(model => model.BookDetail.BookTitle, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookTitle, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookTitle) @Html.LabelFor(model => model.BookDetail.BookAuthor, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookAuthor, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookAuthor) @Html.LabelFor(model => model.BookDetail.BookCategory, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookCategory, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookCategory) @Html.LabelFor(model => model.BookDetail.BookPublisher, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookPublisher, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookPublisher) </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">Save changes</button> </div> }
@model BootstrapDemo.Models.BooksViewModel <link rel="stylesheet" href="~/Content/bootstrap.min.css" /> <script type="text/javascript" src="~/Scripts/bootstrap.min.js"></script> @using (Html.BeginForm("Edit","Home", FormMethod.Post)) { @Html.AntiForgeryToken() <h3 class="modal-title">Edit Book Details</h3> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.BookDetail.BookSerialNo) <div class="modal-body"> @Html.LabelFor(model => model.BookDetail.BookISBN, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookISBN, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookISBN) @Html.LabelFor(model => model.BookDetail.BookTitle, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookTitle, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookTitle) @Html.LabelFor(model => model.BookDetail.BookAuthor, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookAuthor, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookAuthor) @Html.LabelFor(model => model.BookDetail.BookCategory, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookCategory, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookCategory) @Html.LabelFor(model => model.BookDetail.BookPublisher, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookPublisher, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.BookDetail.BookPublisher) </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">Save changes</button> </div> }
@model BootstrapDemo.Models.BooksViewModel <link rel="stylesheet" href="~/Content/bootstrap.min.css" /> <script type="text/javascript" src="~/Scripts/bootstrap.min.js"></script> @using (Html.BeginForm("Delete", "Home", FormMethod.Post)) { @Html.AntiForgeryToken() <h3 class="modal-title">Delete this Book Item?</h3> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.BookDetail.BookSerialNo) <div class="modal-body"> @Html.LabelFor(model => model.BookDetail.BookISBN, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookISBN, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookTitle, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookTitle, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookAuthor, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookAuthor, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookCategory, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookCategory, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookPublisher, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookPublisher, new { @class = "form-control ", @readonly = "readonly" }) </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">Delete</button> </div> }
@model BootstrapDemo.Models.BooksViewModel <link rel="stylesheet" href="~/Content/bootstrap.min.css" /> <script type="text/javascript" src="~/Scripts/bootstrap.min.js"></script> @using (Html.BeginForm("Details", "Home", FormMethod.Post)) { @Html.AntiForgeryToken() <h3 class="modal-title">Book Details</h3> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.BookDetail.BookSerialNo) <div class="modal-body"> @Html.LabelFor(model => model.BookDetail.BookISBN, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookISBN, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookTitle, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookTitle, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookAuthor, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookAuthor, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookCategory, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookCategory, new { @class = "form-control", @readonly = "readonly" }) @Html.LabelFor(model => model.BookDetail.BookPublisher, new { @class = "control-label" }) @Html.TextBoxFor(model => model.BookDetail.BookPublisher, new { @class = "form-control ", @readonly = "readonly" }) </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button> </div> }
I spent a whole day trying to get Modal Bootstrap to work. Most tutorials are just way too complicated or lack all of the code necessary. This is example is simple and to the point... and works.
ReplyDeleteCool! Thanks for the kind words and I'm glad that my blog post was simple enough to get you started with Bootstrap Modal.
DeleteCheers!
how to check model validations ?
ReplyDeleteHi, you can apply the concept of Data Annotation to validate your model.
DeleteThank you for the detailed explanation.
ReplyDeleteYou're welcome. Glad it helped you!
Delete