CRUD in ASP.NET MVC 4 with KnockOut.JS






4.50/5 (13 votes)
This tip will help beginners to implement CRUD operations in ASP.NET MVC 4 with scripting language as KnockOut and Database as MS SQL 2008R2.
Introduction
As you know, Knockout is a JavaScript library that allows you to bind html elements to any data model. You can also use Knockout for Insert
, Update
, Delete
and Retrieve
operations. This tip will demonstrate how to use Knockout with MVC4 for CRUD (Create
, Read
, Update
, Delete
) operations. Many experienced developers will find this tip very basic, but since the tip is written from the perspective of beginners, I've tried to keep things simple.
Background
If you don't have basic knowledge of Knockout JS, kindly refer to this excellent article.
Using the Code
Let's begin !!!
Create 'TblProductList
' table with this schema.
Create a new project in ASP.NET MVC 4 and name it as you prefer and select empty project template.
Install Entity Framework 6, Jquery and Knockout in your project using NuGet Package Manager.
You can also download jquery.js and Knockout.js from their official website and paste it in 'Scripts' folder of your project.
Right Click on Model folder and add a new ADO.NET Entity Data Model. Name it as 'ProductDataContext.edmx'.
Choose 'Generate from Database' and configure the connection string as per your SQL server.
After generating the model, you will get the entity of TblProductList
.
Create new folder 'Interface' in root directory. Add a new class 'IProductRepository.cs'.
interface IProductRepository
{
IEnumerable<TblProductList> GetAll();
TblProductList Get(int id);
TblProductList Add(TblProductList item);
bool Update(TblProductList item);
bool Delete(int id);
}
Create new folder 'Repositories' in root directory. Add a new class 'ProductRepository.cs'.
Implement the methods to Create
, Read
, Update
, Delete
using Entity Framework.
public class ProductRepository : IProductRepository
{
ProductDBEntities ProductDB = new ProductDBEntities();
public IEnumerable<TblProductList> GetAll()
{
// TO DO : Code to get the list of all the records in database
return ProductDB.TblProductLists;
}
public TblProductList Get(int id)
{
// TO DO : Code to find a record in database
return ProductDB.TblProductLists.Find(id);
}
public TblProductList Add(TblProductList item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
// TO DO : Code to save record into database
ProductDB.TblProductLists.Add(item);
ProductDB.SaveChanges();
return item;
}
public bool Update(TblProductList item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
// TO DO : Code to update record into database
var products = ProductDB.TblProductLists.Single(a => a.Id == item.Id);
products.Name = item.Name;
products.Category = item.Category;
products.Price = item.Price;
ProductDB.SaveChanges();
return true;
}
public bool Delete(int id)
{
// TO DO : Code to remove the records from database
TblProductList products = ProductDB.TblProductLists.Find(id);
ProductDB.TblProductLists.Remove(products);
ProductDB.SaveChanges();
return true;
}
}
Right click on Controllers folder and add new Controller 'ProductController.cs':
public class ProductController : Controller
{
static readonly IProductRepository repository = new ProductRepository();
public ActionResult Products()
{
return View();
}
public JsonResult GetAllProducts()
{
return Json(repository.GetAll(), JsonRequestBehavior.AllowGet);
}
public JsonResult AddProduct(TblProductList item)
{
item = repository.Add(item);
return Json(item, JsonRequestBehavior.AllowGet);
}
public JsonResult EditProduct(int id, TblProductList product)
{
product.Id = id;
if (repository.Update(product))
{
return Json(repository.GetAll(), JsonRequestBehavior.AllowGet);
}
return Json(null);
}
public JsonResult DeleteProduct(int id)
{
if (repository.Delete(id))
{
return Json(new { Status = true }, JsonRequestBehavior.AllowGet);
}
return Json(new { Status = false }, JsonRequestBehavior.AllowGet);
}
}
Right click on ActionResult Products()
and add a view 'Products.cshtml'.
@{
ViewBag.Title = "Products List";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@section scripts {
<link href="~/Content/CustomStyle.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/knockout-2.2.0.js"></script>
<script src="~/Scripts/knockout-2.2.0.debug.js"></script>
<script src="~/Scripts/KnockoutDemo.js"></script>
}
<div id="body">
<h2>Knockout CRUD Operations with MVC4</h2>
<h3>List of Products</h3>
<table id="products1" data-bind="visible: Products().length > 0">
<thead>
<tr>
<th style="display: none;">ID</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody data-bind="foreach: Products">
<tr>
<td data-bind="visible:false , text: Id "></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Category"></td>
<td data-bind="text: formatCurrency(Price)"></td>
<td>
<button data-bind="click: $root.edit">Edit</button>
<button data-bind="click: $root.delete">Delete</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6">
<hr />
</td>
</tr>
<tr>
<td>Total :</td>
<td></td>
<td data-bind="text: formatCurrency($root.Total())"></td>
<td></td>
</tr>
</tfoot>
</table>
<br />
<div style="border-top: solid 2px #282828; width: 430px; height: 10px"> </div>
<div data-bind="if: Product">
<div>
<h2>Update Product</h2>
</div>
<div>
<label for="productId" data-bind="visible: false">ID</label>
<label data-bind="text: Product().Id, visible: false"></label>
</div>
<div>
<label for="name">Name</label>
<input data-bind="value: Product().Name" type="text" title="Name" />
</div>
<div>
<label for="category">Category</label>
<input data-bind="value: Product().Category" type="text" title="Category" />
</div>
<div>
<label for="price">Price</label>
<input data-bind="value: Product().Price" type="text" title="Price" />
</div>
<br />
<div>
<button data-bind="click: $root.update">Update</button>
<button data-bind="click: $root.cancel">Cancel</button>
</div>
</div>
<div data-bind="ifnot: Product()">
<div>
<h2>Add New Product</h2>
</div>
<div>
<label for="name">Name</label>
<input data-bind="value: $root.Name" type="text" title="Name" />
</div>
<div>
<label for="category">Category</label>
<input data-bind="value: $root.Category" type="text" title="Category" />
</div>
<div>
<label for="price">Price</label>
<input data-bind="value: $root.Price" type="text" title="Price" />
</div>
<br />
<div>
<button data-bind="click: $root.create">Save</button>
<button data-bind="click: $root.reset">Reset</button>
</div>
</div>
</div>
Create a new JavaScript file 'KnockoutDemo.js' in Scripts folder to implement CRUD operations using Knockout code.
function formatCurrency(value) {
return "₹ " + value.toFixed(2);
}
function ProductViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
self.Product = ko.observable();
self.Products = ko.observableArray(); // Contains the list of products
// Initialize the view-model
$.ajax({
url: 'Product/GetAllProducts',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Products(data); //Put the response in ObservableArray
}
});
// Calculate Total of Price After Initialization
self.Total = ko.computed(function () {
var sum = 0;
var arr = self.Products();
for (var i = 0; i < arr.length; i++) {
sum += arr[i].Price;
}
return sum;
});
//Add New Item
self.create = function () {
if (Product.Name() != "" &&
Product.Price() != "" && Product.Category() != "") {
$.ajax({
url: 'Product/AddProduct',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Product),
success: function (data) {
self.Products.push(data);
self.Name("");
self.Price("");
self.Category("");
}
}).fail(
function (xhr, textStatus, err) {
alert(err);
});
}
else {
alert('Please Enter All the Values !!');
}
}
// Delete product details
self.delete = function (Product) {
if (confirm('Are you sure to Delete "' + Product.Name + '" product ??')) {
var id = Product.Id;
$.ajax({
url: 'Product/DeleteProduct/' + id,
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: id,
success: function (data) {
self.Products.remove(Product);
}
}).fail(
function (xhr, textStatus, err) {
self.status(err);
});
}
}
// Edit product details
self.edit = function (Product) {
self.Product(Product);
}
// Update product details
self.update = function () {
var Product = self.Product();
$.ajax({
url: 'Product/EditProduct',
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Product),
success: function (data) {
self.Products.removeAll();
self.Products(data); //Put the response in ObservableArray
self.Product(null);
alert("Record Updated Successfully");
}
})
.fail(
function (xhr, textStatus, err) {
alert(err);
});
}
// Reset product details
self.reset = function () {
self.Name("");
self.Price("");
self.Category("");
}
// Cancel product details
self.cancel = function () {
self.Product(null);
}
}
var viewModel = new ProductViewModel();
ko.applyBindings(viewModel);
Add a Layout view '_Layout.cshtml'.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<meta name="viewport" content="width=device-width" />
</head>
<body>
<div id="body">
@RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
@RenderBody()
</section>
</div>
@RenderSection("scripts", required: false)
</body>
</html>
Add stylesheet 'CustomStyle.css' to improve the look and feel of the page.
body {
margin: 20px;
font-family: "Arial", "Helventica", sans-serif;
}
label {
width: 80px;
display: inline-block;
}
button {
display: inline-block;
outline: none;
cursor: pointer;
text-align: center;
text-decoration: none;
padding: .4em 1.1em .4em;
color: #fef4e9;
border: solid 1px #006fb9;
background: #1276bb;
}
button:hover {
text-decoration: none;
background: #282828;
border: solid 1px #000;
}
table {
padding-top: 1em;
}
thead, tfoot {
font-weight: 600;
}
th, td {
padding: .1em .5em;
text-align: left;
}
td li, td ul {
margin: 0;
padding: 0;
}
td li {
display: inline;
}
td li::after {
content: ',';
}
td li:last-child::after {
content: '';
}
Now, change the default controller and action in Route.Config.cs.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Product", action = "Products", id = UrlParameter.Optional }
);
Hit Ctrl+F5.
That's it !!!
Congratulations !!! Now you have successfully implemented CRUD operations in ASP.NET MVC 4 using Knockout.js.
Please comment for any queries.
Source Code
I have uploaded a sample project with SQL scripts, in case you need them. Don't forget to change the server name in Web.Config.
HAPPY CODING! :)