Saturday, January 23, 2016

Knockout js Introduction

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 
Description: http://www.codeproject.com/KB/scripting/680553/MVVM.png
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
·         Minified version: http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js
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 Description: http://www.codeproject.com/images/arrow-up-16.png   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:
Description: http://www.codeproject.com/KB/scripting/680553/EmployeeEntryForm.png 
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. 
Description: http://www.codeproject.com/KB/scripting/680553/BindingKeywords.png
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.
Description: http://www.codeproject.com/KB/scripting/680553/AfterDataSubmit.png 
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 
Description: http://www.codeproject.com/KB/scripting/680553/EmployeePhoneNumberEntryForm.png 
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  
·         http://knockoutjs.com 


No comments:

Post a Comment