Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps

CRUD in ASP.NET MVC 4 with KnockOut.JS

4.50/5 (13 votes)
20 Jan 2016CPOL2 min read 55.5K   2.7K  
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.

Image 1

Create a new project in ASP.NET MVC 4 and name it as you prefer and select empty project template.

Image 2

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'.

Image 3

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.

Image 4

Create new folder 'Interface' in root directory. Add a new class 'IProductRepository.cs'.

C#
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.

C#
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':

C#
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'.

HTML
@{
    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.

JavaScript
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'.

HTML
<!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.

CSS
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.

C#
routes.MapRoute(
              name: "Default",
              url: "{controller}/{action}/{id}",
              defaults: new { controller = "Product", action = "Products", id = UrlParameter.Optional }
           );

Hit Ctrl+F5.

That's it !!!

Image 5


Image 6


Image 7

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! :)

Reference

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)