This article explains how to use the Model View ViewModel (MVVM) pattern with Knockout using Entity Framework in ASP.Net web applications.

MVVM: The MVVM pattern solves the problem of de-coupling the View from the Model, so that Views can be implemented by the designers instead of software developers.

Knockout: KnockoutJS is a pure JavaScript framework to implement the MVVM design pattern in the web application development. The main key concepts of KO is:

Getting Started

This is the employee table entity data diagram:

entity data diagram

This is model class:
  1. public partial class Employee
  2. {
  3. public Employee()
  4. {
  5. this.Employees1 = new HashSet<Employee>();
  6. }
  7. public int EmployeeID { get; set; }
  8. public string LastName { get; set; }
  9. public string FirstName { get; set; }
  10. public string Title { get; set; }
  11. public string TitleOfCourtesy { get; set; }
  12. public Nullable<System.DateTime> BirthDate { get; set; }
  13. public Nullable<System.DateTime> HireDate { get; set; }
  14. public string Address { get; set; }
  15. public string City { get; set; }
  16. public string Region { get; set; }
  17. public string PostalCode { get; set; }
  18. public string Country { get; set; }
  19. public string HomePhone { get; set; }
  20. public string Extension { get; set; }
  21. public byte[] Photo { get; set; }
  22. public string Notes { get; set; }
  23. public string PhotoPath { get; set; }
  24. public virtual ICollection<Employee> Employees1 { get; set; }
  25. public virtual Employee Employee1 { get; set; }
  26. }

This is the context class:

  1. public partial class NorthwindEntities2 : DbContext
  2. {
  3. public NorthwindEntities2() : base("name=NorthwindEntities2")
  4. {
  5. }
  6. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  7. {
  8. throw new UnintentionalCodeFirstException();
  9. }
  10. public DbSet<Employee> Employees { get; set; }
  11. }

Add these js, assembly references.

assembly references

Now for the ViewModel.

  1. <script src="Scripts/jquery-1.10.2.js"></script>
  2. <script src="Scripts/knockout-3.0.0.js"></script>
  3. <script type="text/javascript">
  4. function Employee(data) {
  5. this.EmployeeID = ko.observable(data.EmployeeID);
  6. this.LastName = ko.observable(data.LastName);
  7. this.FirstName = ko.observable(data.FirstName);
  8. this.Address = ko.observable(data.Address);
  9. this.City = ko.observable(data.City);
  10. this.Region = ko.observable(data.Region);
  11. this.PostalCode = ko.observable(data.PostalCode);
  12. this.Country = ko.observable(data.Country);
  13. this.PhotoPath = ko.observable(data.PhotoPath);
  14. }
  15. // View Model
  16. function EmployeeViewModel() {
  17. var self = this;
  18. self.Countries = ko.observableArray(['USA', 'UK', 'India']);
  19. self.Employees = ko.observableArray([]);
  20. self.EmployeeID = ko.observable();
  21. self.LastName = ko.observable();
  22. self.FirstName = ko.observable();
  23. self.Address = ko.observable();
  24. self.City = ko.observable();
  25. self.Region = ko.observable();
  26. self.PostalCode = ko.observable();
  27. self.Country = ko.observable();
  28. self.PhotoPath = ko.observable();
  29. self.AddEmployee = function () {
  30. self.Employees.push(new Employee({
  31. EmployeeID: self.EmployeeID(),
  32. LastName: self.LastName(),
  33. FirstName: self.FirstName(),
  34. Address: self.Address(),
  35. City: self.City(),
  36. Region: self.Region(),
  37. PostalCode: self.PostalCode(),
  38. Country: self.Country(),
  39. PhotoPath: self.PhotoPath()
  40. }));
  41. self.EmployeeID("");
  42. self.LastName("");
  43. self.FirstName("");
  44. self.Address("");
  45. self.City("");
  46. self.Region("");
  47. self.PostalCode("");
  48. self.Country("");
  49. self.PhotoPath("");
  50. };
  51. //Remove from list
  52. self.RemoveEmployee = function (employee) {
  53. self.Employees.remove(employee)
  54. };
  55. // Save data in database
  56. self.SaveToDb = function () {
  57. jQuery.ajax({
  58. type: "POST",
  59. url: "http://localhost:16072/Default.aspx/SaveEmployees",
  60. data: ko.toJSON({ data: self.Employees }),
  61. contentType: "application/json",
  62. success: function (result) {
  63. alert(result.d);
  64. }
  65. });
  66. };
  67. //Delete Employee
  68. self.DeleteEmployee = function () {
  69. jQuery.ajax({
  70. type: "POST",
  71. url: "http://localhost:16072/Default.aspx/DeleteEmployee",
  72. data: ko.toJSON({ data: self.Employees }),
  73. contentType: "application/json",
  74. success: function (result) {
  75. alert(result.d);
  76. self.Students.remove(student)
  77. },
  78. error: function (err) {
  79. alert(err.status + " - " + err.statusText);
  80. }
  81. });
  82. };
  83. //get EMployee
  84. $.ajax({
  85. type: "POST",
  86. url: 'http://localhost:16072/Default.aspx/GetEmployees',
  87. contentType: "application/json; charset=utf-8",
  88. dataType: "json",
  89. success: function (results) {
  90. var employees = $.map(results.d, function (item) {
  91. return new Employee(item)
  92. });
  93. self.Employees(employees);
  94. },
  95. error: function (err) {
  96. alert(err.status + " - " + err.statusText);
  97. }
  98. });
  99. }
  100. //KO binding
  101. $(document).ready(function () {
  102. ko.applyBindings(new EmployeeViewModel());
  103. });
  104. </script>

Code Behind

  1. [WebMethod]
  2. public static Employee[] GetEmployees()
  3. {
  4. var dbContext = new NorthwindEntities2();
  5. var data = (from item in dbContext.Employees
  6. orderby item.EmployeeID
  7. select item).Take(5);
  8. return data.ToArray();
  9. }
  10. [WebMethod]
  11. public static string SaveEmployees(Employee[] data)
  12. {
  13. var dbContext = new NorthwindEntities2();
  14. var employeeList = from dbEmployee in dbContext.Employees select dbEmployee;
  15. foreach (Employee employeeOld in data)
  16. {
  17. var employee = new Employee();
  18. if (employeeOld != null)
  19. {
  20. employee.EmployeeID = employeeOld.EmployeeID;
  21. employee.FirstName = employeeOld.FirstName;
  22. employee.LastName = employeeOld.LastName;
  23. employee.Address = employeeOld.Address;
  24. employee.City = employeeOld.City;
  25. employee.Region = employeeOld.Region;
  26. employee.PostalCode = employeeOld.PostalCode;
  27. employee.Country = employeeOld.Country;
  28. employee.PhotoPath = employeeOld.PhotoPath;
  29. }
  30. Employee emp = (from em in employeeList
  31. where
  32. em.EmployeeID == employee.EmployeeID
  33. select em).FirstOrDefault();
  34. if (emp == null)
  35. dbContext.Employees.Add(employee);
  36. dbContext.SaveChanges();
  37. }
  38. return "Employee saved to database!";
  39. }
  40. [WebMethod]
  41. public static string DeleteEmployee(Employee data)
  42. {
  43. try
  44. {
  45. var dbContext = new NorthwindEntities2();
  46. var employee = dbContext.Employees.FirstOrDefault
  47. (userId => userId.EmployeeID == data.EmployeeID);
  48. if (employee != null)
  49. {
  50. if (employee != null)
  51. {
  52. dbContext.Employees.Remove(employee);
  53. dbContext.SaveChanges();
  54. }
  55. }
  56. return "Employee deleted from database!";
  57. }
  58. catch (Exception ex)
  59. {
  60. return "Error: " + ex.Message;
  61. }
  62. }

Now to display the data:

  1. <form id="form1" runat="server">
  2. <h3>Add New Employee</h3>
  3. <table>
  4. <tr>
  5. <td>Employee ID :</td>
  6. <td><input data-bind="value: EmployeeID" /></td>
  7. </tr>
  8. <tr>
  9. <td>Last Name :</td>
  10. <td><input data-bind="value: LastName" /></td>
  11. </tr>
  12. <tr>
  13. <td>First Name :</td>
  14. <td>
  15. <input data-bind="value: FirstName" /></td>
  16. </tr>
  17. <tr>
  18. <td>Address :</td>
  19. <td><input data-bind="value: Address" /></td>
  20. </tr>
  21. <tr>
  22. <td>City :</td>
  23. <td><input data-bind="value: City" /></td>
  24. </tr>
  25. <tr>
  26. <td>Region :</td>
  27. <td><input data-bind="value: Region" /></td>
  28. </tr>
  29. <tr>
  30. <td>Postal Code :</td>
  31. <td><input data-bind="value: PostalCode" /></td>
  32. </tr>
  33. <tr>
  34. <td>Country :</td>
  35. <td><select data-bind="options: Countries, value: Country, optionsCaption: 'Select Country...'"></select>
  36. </td>
  37. </tr>
  38. <tr>
  39. <td>Photo Path :</td>
  40. <td><input data-bind="value: PhotoPath" /></td>
  41. </tr>
  42. <tr>
  43. <td colspan="2">
  44. <button type="button" data-bind="click: AddEmployee">Add Employee</button>
  45. <button type="button" data-bind="click: SaveToDb">Save To Database</button>
  46. </td>
  47. </tr>
  48. </table>
  49. <table data-bind="visible: Employees().length > 0" border="0">
  50. <tr>
  51. <th>Employee ID</th>
  52. <th>Last Name</th>
  53. <th>First Name</th>
  54. <th>Adress</th>
  55. <th>City</th>
  56. <th>Region</th>
  57. <th>PostalCode</th>
  58. <th>Country</th>
  59. <th>Photo</th>
  60. <th>Action</th>
  61. </tr>
  62. <tbody data-bind="foreach: Employees">
  63. <tr>
  64. <td><span data-bind="text: EmployeeID" /></td>
  65. <td><input data-bind="value: LastName" /></td>
  66. <td><input data-bind="value: FirstName" /></td>
  67. <td><input data-bind="value: Address" /></td>
  68. <td><input data-bind="value: City" /></td>
  69. <td><input data-bind="value: Region" /></td>
  70. <td><input data-bind="value: PostalCode" /></td>
  71. <td><select data-bind="options: $root.Countries, value: Country"></select></td>
  72. <td><input data-bind="value: PhotoPath" /></td>
  73. <td><a href="#" data-bind="click: $root.RemoveEmployee">Remove From List</a></td>
  74. <td><a href="#" data-bind="click: $root.DeleteEmployee">Delete From DataBase</a></td>
  75. </tr>
  76. </tbody>
  77. </table>
  78. </form>

Run sample


Run application