Dear All,
Feeling great J
after long years gap starting again writing my blog,
Introduction
Knockout js (shortly called KO) is a very popular JavaScript library and increasing
its popularity day by day. This library helps to create
rich/responsive/interactive web applications. It works directly with the web
application's underlying data model. Using KO with any web application is very simple,
clean, and straightforward, it is very powerful in the context of dynamic UI
creation.
Background
JavaScript plays a
very important role for developing today's modern web applications. Once upon a
time, we just wrote a few JavaScript lines for data validation from the client
side. But day by day JavaScript plays a vital role not only in data validation
but also for creating responsive, robust web UI. For that reason, day by day a
new JavaScript framework/library comes into market. We as smart developers,
must adopt them and try to use them with our applications.
Benefits
If we use KO with web
applications, we can get following benefits
·
Anytime we can connect UI elements with data model.
·
Easily create complex dynamic data model.
·
Automatically update UI when Data Model is changed, when UI is
changed then Data Model is changed automatically.
·
Support event-driven programming model.
·
Extend custom behavior very easily.
·
All main-stream browsers are supported (IE, FireFox, Crome,
Safari)
KO with MVVM
What is MVVM? Well,
The full form of MVVM is Model View ViewModel. It is an architectural design
pattern origined by Microsoft and mainly created for WPF/Silverlight
applications. But we can use this Web application too with
ASP.NET.
MVVM is a specific
implementation targeted at UI development platform which support event driven
programming for WPF/Silverlight. It respect the programming principle
"Separation of Concern". It completely separate GUI Rendering logic
from Application Logic (Data Logic/Business Logic).
KO built on that
architectural design pattern. So if you want to understand KO properly then you
should know about MVVM first.
MVVM Overview
The following diagram
will show the style of MVVM

MVVM has 3 parts:
1.
Model
2.
View
3.
ViewModel
·
Model: Responsible for
holding Application data. When User enter data with UI elements,
That data will store to a Model. So we can thinks like it is data part of the
pattern.
·
View: Responsible
for presenting model data to the user. User elements are the part of the View.
It provide structure/Layout of the User Interface and present to the user.
·
ViewModel:
Connector of Model and View. Main responsibility is establish communication with
View and Model. It hold data and function. Functions manipulate that data and
it reflect to the UI. When data changed, UI is changed, when UI changed data is
changed. ViewModel will does it for us with the help of databinding
concept.
MVVM Benefits
Main benefits of MVVM:
·
Provide more flexibility of designer and developer works.
·
Thorough unit testing
·
Provide flexibility to change user interface without having to
re-factor other logic of the codebase.
·
Provide more re-usability of UI component.
Include KO library to Web Application
CDN (Content Delivery
Network) reference of Knockout js is available at Microsoft CDN repository.
There are two versions available. One for compact (minified) another for debug.
It is recommended to use minified version. The url are
If your application is
ASP.NET WebForm then you can download js file from above locations and store it
to your web folder/subfolder and reference it to your page/master page.
Hide Copy Code
<script src="~/Scripts/knockout-2.2.1.js" type="text/javascript"></script>
CDN Reference:
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js" type="text/javascript"></script>
If ASP.NET MVC
application you can take reference inside @section
Hide Copy Code
@section scripts {
<script src="~/Scripts/knockout-2.2.1.js"></script>
}
CDN Reference:
@section scripts {
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
}
Example-1
I will create a simple
Employee information entry form. Form will accept some basic employee related
data from the user and submit that data to the MVC Action with the help of
AJAX. In View part , I will use various html element so that I can show how all
elements are worked with KO.
Implementation:
Before start showing
code with KO just mention one thing. In MVVM pattern, a personal choice
is there. That is which come first, Model Or View. I am not going to discuss
detail on that. Just mention my personal preference and that is View. I always
like to start View first then for Model.
Hide Shrink
Copy Code
<form id="employeeForm" name="employeeForm" method="POST">
<div id="form-root">
<div>
<label class="form-label">First
Name:</label>
<input type="text" id="txtFirstName"
name="txtFirstName" data-bind="value:Employee.FirstName" />
</div>
<div>
<label class="form-label">Last Name:</label>
<input type="text" id="txtLastName"
name="txtLastName" data-bind="value:Employee.LastName" />
</div>
<div>
<label class="form-label">Full
Name:</label>
<input type="text" id="txtFullName" name="txtFullName"
data-bind="value:Employee.FullName" readonly="readonly" />
</div>
<div>
<label class="form-label">Date
Of Birth:</label>
<input type="text" id="txtDateOfBirth"
name="dateOfBirth" data-bind="value:Employee.DateOfBirth" />
</div>
<div>
<label>Education:</label>
<input type="checkbox" value="graduation" id="chkGraduation"
name="chkGraduation" data-bind="checked:Employee.EducationList" />Graduation
<input type="checkbox" value="postGraduation"
id="chkPostGraduation" name="chkPostGraduation"
data-bind="checked:Employee.EducationList" />PostGraduation
</div>
<div>
<label>Gender:</label>
<input type="radio" id="rdoMale" name="gender"
value="0" data-bind="checked:Employee.Gender" />Male
<input type="radio" id="rdoFeMale" name="gender"
value="1" data-bind="checked:Employee.Gender" />FeMale
</div>
<div>
<label class="form-label">Department:</label>
<select id="ddlDepartment" name="ddlDepartment"
data-bind="options:$root.Employee.DepartmentList,
optionsValue:'Id',
optionsText:'Name', value:Employee.DepartmentId">
</select>
</div>
<div>
<input type="button" id="btnSubmit"
value="Submit" data-bind = "click: submit" />
<input type="button" id="btnReset"
value="Reset" data-bind = "click: reset" />
</div>
</div>
</form>
View:
First I create a
view.Its looks like:
I bind all of view's
html form element with my client side model with KO's data-bind
attribute. Why i said Client Side Model? Because i have a Server
Side Model too. Letter I talk about server side model. With Data-Bind
attribute, KO connect UI element to the Model property. Now explain UI elements
connect to the Data Memeber of the Model one by one.
TextBox Binding:
Hide Copy Code
<input type="text" id="txtFirstName" name="txtFirstName" data-bind="value:Employee.FirstName" />
Html form element
textbox bind with FirstName property of Employee Model. value is the KO key by
which KO address textbox value property. But remember that value inside
data-bind attribute is the KO's key not html native. When textbox value is
updated then FirstName property of the Employee model will be updated
automatically and vice-versa. No custom code is needed for that.
CheckBox Binding:
Hide Copy Code
<input type="checkbox" value="graduation"
id="chkGraduation" name="chkGraduation" data-bind="checked:Employee.EducationList" />
<input type="checkbox" value="postGraduation" id="chkPostGraduation"
name="chkPostGraduation" data-bind="checked:Employee.EducationList" />
HTML form element
checkbox (input checkbox) is bind with EducationList string array of Employee
Model. Here both checkbox is bind with single model property. When user checked
any/both checkbox, automatically the value of the checkboxes (1st checkbox
value is "graduation" 2nd is "PostGraduation") will
be added to the array. If un-checked then the value will be removed from this
array. In textbox we use KO's key value, in checkbox here we use another KO's
key named checked. Again checked in not any HTML native.
Radio-Button Binding:
Hide Copy Code
<input type="radio" id="rdoMale" name="gender"
value="0" data-bind="checked:Employee.Gender" />
<input type="radio" id="rdoFeMale" name="gender"
value="1" data-bind="checked:Employee.Gender" />
There are two radio
buttons and grouped it with name property. If radio-buttons name is same then
they work like group. If one radio is selected then automatically others will
be de-selected and vice-versa. Both radio buttons are bind with single Employee
Model property named Gender (number type). When Male will select then this
property will contain 0, if FeMale select, it will contain 1. Same way
when Gender contain 0 then rdoMale radio will be selected, when Gender contain
1 then rdoFemale will be selected (checked).
Drop-Down/ComboBox/Select
Binding:
Hide Copy Code
<select id="ddlDepartment" name="ddlDepartment"
data-bind="options:$root.Employee.DepartmentList,
optionsValue:'Id',
optionsText:'Name',
value:Employee.DepartmentId">
</select>
Drop-down list is bind
with two Model properties. For its data source, it binds DepartmentList array
of object of Employee Model. Object has 2 properties. Id and Name. Id Bind with
value and Name bind with option text. Means, drop-down will show all Name of
the objects. Drop-down selected value is bind with DepartmentId property. When
user select any item from drop-down, the value of the item will store in
DepartmentId. Sameway if any value assign to the DepartmentId from the
ViewModel then drop-down will show that item which match the value to the user.
Button/Command Button Binding:
Hide Copy Code
<input type="button" id="btnSubmit" value="Submit" data-bind = "click: submit" />
Button is bind with
submit method of the ViewModel with click event. When user click Submit button
then submit method of the ViewModel will fire.
There are so many
keywords are used in data-binding in KO. All are KO's own keyword. It should be
clear that those are not HTML native property.

Model:
Hide Copy Code
function Employee() {
var that = this;
that.FirstName =
ko.observable("");
that.LastName =
ko.observable("");
that.FullName =
ko.computed(function () {
return that.FirstName() + " " + that.LastName();
});
that.DateOfBirth =
ko.observable("");
that.EducationList =
ko.observableArray();
that.Gender =
ko.observable("0");
that.DepartmentList =
ko.observableArray([{ Id: '0', Name: "CSE" }, { Id: '1', Name: "MBA" }]);
that.DepartmentId = ko.observable("1");
}
Employee is my Model.
We can call it data model. In its every property i initialize with ko.observable method.
What does the actual ko.observable method return? It returns a function, which notify ui
element for update. So in property of Employee like FirstName, LastName etc all
are functions. If I want to assign any value to the FirstName then code should
be that.FirstName("Mr."), if read that property then it should be
that.FirstName() computed is another ko library function which is
responsible for dependency tracking. Means, inside that function i use
FirstName and LastName property. When FirstName or LastName property is updated
then fullName is automatically updated.
KO has another
important things that is Observable Array. It is nothing but a collection of
observable method. Each and every item of array will be observable. If i
want to add value to that array then i need to use
Hide Copy Code
that.DepartmentList.push({Id:3, Name:"BBA"});
If want to remove last
item of the array the
Hide Copy Code
that.DepartmentList.pop();
It might be confused
that push and pop are the javascript array native method. But here use push and
pop with observable array are not the native javascript method. It is actually
KO's own implemented method. KO implements 6 methods for observable array.
1.
push
2.
pup
3.
unshift
4.
shift
5.
reverse
6.
sort
So be clear on that
and not to confuse javascript array object's method with that.
ViewModel:
Hide Copy Code
function EmployeeVM() {
var that = this;
that.Employee = new Employee();
that.reset = function () {
that.Employee.FirstName("");
that.Employee.LastName("");
that.Employee.DateOfBirth("");
};
that.submit = function () {
var json1 = ko.toJSON(that.Employee);
$.ajax({
url: '/Employee/SaveEmployee',
type: 'POST',
dataType: 'json',
data: json1,
contentType: 'application/json; charset=utf-8',
success: function (data) {
var message = data.Message;
}
});
};
};
that.Employee is hold
the reference of Employee Model. Here i implement 2 behaviors
1. reset: reset method will re-initialize the
value of the model.
2. submit: convert Employee model data to jason string
and send it to the server's SaveEmployee action method with the help of JQuery
ajax method.
Controller
Action:
Hide Copy Code
[HttpPost]
public
ActionResult SaveEmployee(Employee emp)
{
//EmployeeModel save code here
return View("EmployeeInfo");
}
This is the Employee
controller action method. submit method of client side view model send data to
this action method. Actually this action receives data from client view
and process that data then save that data to the database or throw exception if
any invalid things happen.
Server
side Model:
Hide Copy Code
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public Gender Gender { get; set; }
public IList<string> EducationList { get; set; }
public int DepartmentId { get; set; }
}
public enum Gender
{
Male =0,
FeMale = 1
}
This is my server side
Employee Model. Why server side Model is required? We see that from my client
part we create an Employee ViewModel. But it should be in mind that in client
side we actually do not write any business logic. My application process
business logic. Then where i write that? For server side business logic handle,
we create server side Model and we send that model to various layers like
domain service layer/Repository layer etc.
Example-2
I will create an
Employee phone entry form. Employee could have multiple phone number with
country code. First time view will show to add a single phone number entry
option. If user wants than if he press Add button then it will create another
phone number entry option dynamically to the user interface. User can also
remove any phone number entry option with press Remove button. So we understand
that there dynamic ui rendering feature will come. Lets see how knockout will
help in this area.
Implementation:
View:
First i will complete
view creation part. View looks
Hide Copy Code
<form id="employeeForm" name="employeeForm" method="POST">
<script id="PhoneTemplate" type="text/html">
<div>
<span>
<label>Country Code:</label>
<input type="text" id="txtCountryCode" data-bind="value:CountryCode" />
</span>
<span>
<label>Phone Number:</label>
<input type="text" id="txtPhoneNumber" data-bind="value:PhoneNumber" />
</span>
<input type="button" id="btnRemove"
value="Remove" data-bind="click: $parent.remove" />
</div>
</script>
<div>
<h2>Employee
Phone Number</h2>
<div data-bind="template:{name:'PhoneTemplate', foreach:PhoneList},
visible:isVisible">
</div>
<div>
<input type="button" id="btnAdd"
value="Add Another" data-bind="click: add" />
</div>
</div>
</form>
KO supports data
template. It develops template engine for rendering template. This is also
works with jQuery template too. I create a template named PhoneTemplate.
Hide Copy Code
<script id="PhoneTemplate" type="text/html"> </script>
I declare type="text/html"
with script tag. That mean I knotify browser that it is text data and you
will not execute it. Inside that script block I create a div. Inside that
div i create 2 html textbox, 2 labels and 1 button.
Outside the script
block i create another div and bind that div to my javascript viewmodel's array
member PhoneList. KO has its own syntax to bind with template. Here inside the
data-bind attribute I declare,
Hide Copy Code
<div data-bind="template:{name:'PhoneTemplate', foreach:PhoneList}">
</div>
it bind with a
template named 'Phonetemplate' and use foreach statement. That means
render this referenced template equal to no of items found in PhoneList.
If i dynamically add item to the PhoneList then template will render
with again with new UI and same way if i remove item from this array
automatically ui element which renders when item is added will be
removed.
Model:
Hide Copy Code
function Phone(code, number) {
var self = this;
self.CountryCode =
ko.observable(code);
self.PhoneNumber =
ko.observable(number);
}
Client side Javascript
Model has 2 properties
1. CountryCode
2. PhoneNumber
Each property
initialize with observable method so that it can works with KO. This two
properties is used inside template.
ViewModel:
Hide Copy Code
function PhoneViewModel() {
var self = this;
self.PhoneList =
ko.observableArray([new Phone("00", "00-00-00")]);
self.remove = function () {
self.PhoneList.remove(this);
};
self.add = function () {
self.PhoneList.push(new Phone("01", "00-00-01"));
};
}
PhoneViewModel
establish connection between Phone View and Phone Model with the help of
data-bind attribute. This ViewModel contains 2 methods
1. add
2. remove
when user press 'Add
Another" button, It will create a new Phone Model with default value and
add it to the PhoneList array. When PhoneList array is added new item,
automatically UI create a new div based on designed template.
When user press
"Remove" button, it will call remove method of ViewModel and remove
current item from the PhoneList array. When an item is removed from array then
automatically ui is re-populated.
View & ViewModel Relation
When you start
implemting MVVM to your web appliation then one issue might face that is how
many ViewModel needed for a view for vise-versa. Means what type of relation
needed for view and model/ViewModel.
There are few opinion
exists in the market
·
One-View to One-ViewModel
·
Many-Views to many-ViewModels
·
One-View to many-ViewModels
Theare is no hard and
fix rule here. Many people including me support Per View will have single
ViewModel and per ViewModel will have single Model. It will helps us to keep
code simpler and more managable.
If Re-usability
concern then I think, You can use many views with a single ViewModel.
References
No comments:
Post a Comment