In one of the trainings I conducted, I was asked about the use and capabilities of Knockout.js in a MVC 4 application. After showning most of the Knockout + MVC4 capabilities to my client, I decided to write this simple article for all those who are interested in using client side frameworks like Knockout.js and jQuery for application development.
Knockout.js a JavaScript library that can be used to create rich client-side data-bound web applications. The Client-Side data-binding capabilities help implement the MVVM pattern in JavaScript allowing us to build dynamic UI that changes as per user actions without necessarily having to make a server side round trip.
Knockout works well with jQuery and has its own templating engine that uses HTML5 compliant tags for data-binding. However, it can work with other templating engines as well. You can get the further information about knockout.js from www.knockoutjs.com.
In the following article, I have used some features of the knockout.js:
. observable: This is used to define model properties. When these properties are bound with UI and when the value for these properties are updated, automatically the UI elements bound with these properties will be updated with the new value.
E.g. this.EmpName = ko.observable(“Mahesh”); - Here EmpName is the observable property. KO represent an object for the Knockout.js library.
The value of the observable is read as var data= this.EmpNo();
· observableArray: This represents a collection of data elements which required notifications. Typically this is used to bind with the List kind of elements.
E.g this.Employees = ko.observableArray([]);
· applyBindings: This is used to activate knockout for the current HTML document or a specific UI element in HTML document. The parameter for this method is the view-model which is defined in JavaScript. This ViewModel contains the observable, observableArray and various methods.
Various other types of binding are used in this article:
o click: Represents a click event handler added to the UI element so that JavaScript function is called.
o value: This represents the value binding with the UI element’s value property to the property defined into the ViewModel.
o visible: This is used to hide or unhide the UI element based upon the value passed to it’s binding.
o Text: This represent the text value of the parameter passed to the UI element.
Creating an Application using MVC 4, WEB API, jQuery and Knockout.js
For the application, ADO.NET EF is used with the SQL server 2012 database and ‘Company’ database with the following table:
USE [Company]
GO
/****** Object: Table [dbo].[EmployeeInfo] Script Date: 11/25/2012 10:10:09 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[EmployeeInfo](
[EmpNo] [int] IDENTITY(1,1) NOT NULL,
[EmpName] [varchar](50) NOT NULL,
[Salary] [decimal](18, 0) NOT NULL,
[DeptName] [varchar](50) NOT NULL,
[Designation] [varchar](50) NOT NULL,
CONSTRAINT [PK_EmployeeInfo] PRIMARY KEY CLUSTERED
(
[EmpNo] 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
SET ANSI_PADDING OFF
GO
Step 1: Open VS 2012 and create a new MVC 4 application, name it as ‘MVC40_Knockout_App’. Download the knockout.js library from www.knockout.js or use the ‘Manage Nuget Package Manager’ from the context menu of the project by right-clicking on the project and search for Knockout.js.
Step 2: In the project, add the ADO.NET Entity Data Model for the above table. After completing the wizard the model will be displayed as below:
Step 3: Right click on the controller folder and add the new API controller of name ‘EmployeeInfoAPIController’, generate this controller from Entity Framework as below:
You will get methods for HTTP GET, POST, PUT and DELETE by default. You can request for these methods using ajax methods provided in jQuery asynchronously.
Step 3: Add a new empty ‘EmployeeController’ into the project. In this controller class, add a new ‘Create’ method which will return the Create view as below:
public ActionResult Create()
{
return View("Create");
}
Step 4: Add a new Create.cshtml view in the project which is not having any model class. This should be an empty view.
Step 5: Open the ‘Site.css’ inside the ‘Content’ folder and add the following css classes:
.FixedContainer
{
float:right;
height: 250px;
width:500px;
padding:3px;
overflow:auto;
}
.FixedContent
{
height:224px;
overflow:auto;
}
The above CSS will be used for Div tag which are added inside the Create.cshtml for vertical scrollbar.
Step 6: Refer the following JavaScript libraries in the Create.cshtml:
<head>
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/knockout-2.2.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<link href="~/Content/Site.css" rel="stylesheet" />
</head>
Step 7: Add the following HTML inside the view:
<form>
<table>
<tr>
<td>
<!--Bind the TextBoxes in the Table to the observable properties defined into the ViewModel -->
<table id="tbldml">
<tr>
<td>EmpNo</td>
<td><input type="text" id="txteno disabled="disabled" /></td>
</tr>
<tr>
<td>EmpName</td>
<td><input type="text" id="txtename /></td>
</tr>
<tr>
<td>Salary</td>
<td><input type="text" id="txtsal /></td>
</tr>
<tr>
<td>DeptName</td>
<td><input type="text" id="txtdname /></td>
</tr>
<tr>
<td>Designation</td>
<td><input type="text" id="txtdesig /></td>
</tr>
<tr>
<!--The click binding has the JavaScirpt methods passed to it-->
<td><button>Save</button></td>
<td><button>Update</button></td>
</tr>
</table>
</td>
<td>
<div class="FixedContainer">
<!--If the length of the Employees is greater than 0 then visible the Table-->
<table style="border: double">
<thead>
<tr>
<td>EmpNo</td>
<td>EmpName</td>
<td>Salary</td>
<td>DeptName</td>
<td>Designation</td>
<td></td>
</tr>
</thead>
<!--Iterate through an observableArray using foreach-->
<tbody>
<tr style="border: solid">
<td><span></span></td>
<td><span></span></td>
<td><span></span></td>
<td><span></span></td>
<td><span></span></td>
<td><button >Delete</button></td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</table>
</form>
Now if you run the application and navigate to the Create action, the view will be displayed with Textboxes for Employee information and the Table will have only headings.
Step 8: Before closing body tag define the <script> block where the ViewModel will be defined as below:
<script type="text/javascript">
var EmpViewModel = function () {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.EmpNo = ko.observable("0");
self.EmpName = ko.observable("");
self.Salary = ko.observable("");
self.DeptName = ko.observable("");
self.Designation = ko.observable("");
//The Object which stored data entered in the observables
var EmpData = {
EmpNo:self.EmpNo,
EmpName: self.EmpName,
Salary: self.Salary,
DeptName: self.DeptName,
Designation: self.Designation
};
//Declare an ObservableArray for Storing the JSON Response
self.Employees = ko.observableArray([]);
GetEmployees(); //Call the Function which gets all records using ajax call
//Function to perform POST (insert Employee) operation
self.save = function () {
//Ajax call to Insert the Employee
$.ajax({
type: "POST",
url: "http://localhost:50457/api/EmployeeInfoAPI",
data: ko.toJSON(EmpData), //Convert the Observable Data into JSON
contentType: "application/json",
success: function (data)
{
alert("Record Added Successfully");
self.EmpNo(data.EmpNo);
alert("The New Employee Id :" + self.EmpNo());
GetEmployees();
},
error: function ()
{
alert("Failed");
}
});
//Ends Here
};
self.update = function () {
var url = "http://localhost:50457/api/EmployeeInfoAPI/" +self.EmpNo();
alert(url);
$.ajax({
type:"PUT",
url:url,
data: ko.toJSON(EmpData),
contentType: "application/json",
success: function (data)
{
alert("Record Updated Successfully");
GetEmployees();
},
error: function (error)
{
alert(error.status +"<!----!>"+error.statusText);
}
});
};
//Function to perform DELETE Operation
self.deleterec = function (employee) {
$.ajax({
type: "DELETE",
url: "http://localhost:50457/api/EmployeeInfoAPI/" + employee.EmpNo,
success: function (data)
{
alert("Record Deleted Successfully");
GetEmployees();//Refresh the Table
},
error: function (error)
{
alert(error.status + "<--and--> " + error.statusText);
}
});
// alert("Clicked" + employee.EmpNo)
};
//Function to Read All Employees
function GetEmployees() {
//Ajax Call Get All Employee Records
$.ajax({
type: "GET",
url: "http://localhost:50457/api/EmployeeInfoAPI",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
self.Employees(data); //Put the response in ObservableArray
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
//Ends Here
}
//Function to Display record to be updated. This will be
//executed when record is selected from the table
self.getselectedemployee = function (employee) {
self.EmpNo(employee.EmpNo),
self.EmpName(employee.EmpName),
self.Salary(employee.Salary),
self.DeptName(employee.DeptName),
self.Designation(employee.Designation)
};
};
ko.applyBindings(new EmpViewModel());
</script>
In the above Script we have defined an observable for the ‘EmployeeInfo’. The observableArray is used to display data inside the Html table. The object ‘EmpData’ is used to store values for observable which are entered by the end-user for performing Insert and Edit operations. This object will be then converted into JSON, using ‘ko.toJSON’ method.
The function ‘GetEmployees’ makes an ajax call to the WEB API and retrieve all employees. Once the call is successful, this response is passed to the observableArray ‘Employees’. The function ‘save’ makes an ajax call to perform POST operation. Likewise methods ‘update’, ‘deleterec’ are used to perform edit and delete operations respectively. The function ‘getselectedemployee’ is used to display the selected employee information so that the Employee information can be updated.
Step 9: Now we need to bind the UI textboxes with observable defined inside ViewModel, the functions defined inside the ViewModel will be bound with the Buttons. For performing data-binding ‘data-bind’ attribute is used. This is introduced in HTML 5. So change the HTML as below: (marked in yellow)
<form>
<table>
<tr>
<td>
<!--Bind the TextBoxes in the Table to the observable properties defined into the ViewModel -->
<table id="tbldml">
<tr>
<td>EmpNo</td>
<td><input type="text" id="txteno" data-bind="value: $root.EmpNo" disabled="disabled" /></td>
</tr>
<tr>
<td>EmpName</td>
<td>
<input type="text" id="txtename" data-bind="value: $root.EmpName" /></td>
</tr>
<tr>
<td>Salary</td>
<td>
<input type="text" id="txtsal" data-bind="value: $root.Salary" /></td>
</tr>
<tr>
<td>DeptName</td>
<td>
<input type="text" id="txtdname" data-bind="value: $root.DeptName" /></td>
</tr>
<tr>
<td>Designation</td>
<td>
<input type="text" id="txtdesig" data-bind="value: $root.Designation" />
</td>
</tr>
<tr>
<!--The click binding has the JavaScirpt methods passed to it-->
<td><button data-bind="click :$root.save">Save</button></td>
<td><button data-bind="click: $root.update">Update</button></td>
</tr>
</table>
</td>
<td>
<div class="FixedContainer">
<!--If the lenght of the Employees is greater than 0 then visible the Table-->
<table data-bind="visible: Employees().length>0" style="border: double">
<thead>
<tr>
<td>EmpNo</td>
<td>EmpName</td>
<td>Salary</td>
<td>DeptName</td>
<td>Designation</td>
<td></td>
</tr>
</thead>
<!--Iterate through an observableArray using foreach-->
<tbody data-bind="foreach: Employees">
<tr style="border: solid" data-bind="click: $root.getselectedemployee" id="updtr">
<td><span data-bind="text: EmpNo"></span></td>
<td><span data-bind="text: EmpName"></span></td>
<td><span data-bind="text: Salary"></span></td>
<td><span data-bind="text: DeptName"></span></td>
<td><span data-bind="text: Designation"></span></td>
<td>
<button data-bind="click: $root.deleterec">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</table>
</form>
Step 10: Run the application and navigate to the Create action of the Employee controller, the result will be as below:
1. All the Employees are displayed:
2. Enter data into textboxes and click on save, the entry will be added and the newly added record will be displayed at the bottom of the table as below. (Note: EmpNo is Read-Only field)
The newly added entry is as below:
3. Click on the Delete Button and the row will be deleted.
4. Select the row from the table, the details will be displayed into textboxes which can be updated.
Conclusion
Using MVC, WEB API, jQuery and Knockout.js, it is really easy to develop rich, client-side, data-bound web applications. The Observable pattern implemented by KO helps us reduce a lot of boiler-plate code that would be required to build same amount of responsiveness in plain JavaScript.
By using knockout.js and jQuery library, we can build browser compatible, rich Line-of-Business (LOB) applications easily.
Download the entire source code (GitHub)
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @
maheshdotnet or connect with him on
LinkedIn