Click here to Skip to main content
15,879,326 members
Articles / DevOps
Tip/Trick

CRUD in ASP.NET MVC 4 with KnockOut.JS

Rate me:
Please Sign up or sign in to vote.
4.50/5 (13 votes)
20 Jan 2016CPOL2 min read 54K   2.7K   20   10
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)


Written By
Software Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionQuestion about reading data from an already existing data base Pin
Member 1449678012-Jun-19 12:13
Member 1449678012-Jun-19 12:13 
QuestionHaving a problem..No class for ProductDBEntities Pin
James M. Bishop19-Jul-18 1:58
James M. Bishop19-Jul-18 1:58 
QuestionHaving a problem..No class for ProductDBEntities Pin
James M. Bishop16-Jul-18 14:16
James M. Bishop16-Jul-18 14:16 
QuestionThanks: Good effort Pin
salman12772-Sep-17 20:46
salman12772-Sep-17 20:46 
QuestionThank you for sharing Pin
Dr_Sarger_PUA14-Nov-16 1:04
Dr_Sarger_PUA14-Nov-16 1:04 
GeneralGood one for new learners Pin
Vishal_Yelve21-Jan-16 0:49
professionalVishal_Yelve21-Jan-16 0:49 
QuestionTime Display Pin
Member 1227745720-Jan-16 21:22
Member 1227745720-Jan-16 21:22 
AnswerRe: Time Display Pin
Indresh_Prajapati20-Jan-16 21:47
professionalIndresh_Prajapati20-Jan-16 21:47 
PraiseGreat Work Pin
DFX10120-Jan-16 9:40
DFX10120-Jan-16 9:40 
PraiseThank you for sharing Pin
Raju_B20-Jan-16 4:46
Raju_B20-Jan-16 4:46 
Quote:
Thank you for sharing. Nice and simple example to understand.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.