As a web developer, we often have to work with different JavaScript frameworks on a regular basis. In this article I will briefly explain my experience with KnockoutJS library and then talk over specifics around some of the components of KO : Observables, Dependent Observables and Templates.

Background

Knockout.js (KO) is a free open source JavaScript library available under MIT license. It was the outcome of a project started by a Microsoft employee and although it did not come directly from Microsoft it works really well with Asp.net (MVC and Web forms) as well as other server side technologies (eg Rails) since it is a pure javascript library.

What problems are we addressing?

Rich client side user interfaces are too complicated to develop. Although JQuery helps in easy DOM manipulation, it doesn't provide a way for structuring the code in order to keep it clean specially when you add a lot of sophisticated behavior and do lots of different things. KO works directly with the web application's underlying data model and can be used to create rich interactive web applications without having a lot of complicated interrelated event handlers that you need to keep a track of. You can define the behaviour declaratively and these behaviours compose together nicely to achieve a certain functionality.

Hello, Object Oriented JavaScript and declarative bindings

Knockout gives you a way of using the MVVM (Model-View-ViewModel) pattern in the browser. It allows declarative bindings of UI controls to your data model. The viewmodel is a clean, object-oriented representation of your UI's data and behaviors. View is a declarative representation of how the data should be displayed visibly. You can implement sophisticated behaviors just by updating the viewmodel object without having to actually change/add/remove the DOM elements since the framework takes care of synchronizing the things for you and does a lot of heavy lifting for your application (and what a relief that it!)

Let us look at the basics of knockout with an example. First add a reference to the knockout library. Now declare a viewmodel which has information about a person and tell knockout to use this viewmodel.

var viewModel={
    firstName:"Bert"
};
ko.applyBindings(viewModel);

Let us understand bindings in KO by displaying this property from the viewModel on the MVC view.

< p >First Name: < span data-bind="text:firstName"></ span ></ p >

We used the data-bind attribute (something that knockout gives you) to link our regular Html DOM element to the viewModel. In this case we linked the text on the element to the FirstName property on the viewModel.

Next we understand the two way binding in KO. Add an input element so that you can edit the data from screen.At this point both the html elements on the screen are bound to the same underlying property FirstName (Bert) of the viewmodel.

< p > First Name: < input data-bind="value:firstName"/ >< /p >
< p > First Name: < span data-bind="text:firstName">< /span >< /p >

Now edit the FirstName (Bert) inside the textbox and change it to something else (Benny). Nothing seems to happen at this point since the first html element still displays old value(Bert).

Actually, something did happen internally. When you edited the textbox, because it is a two way binding, it updated the firstName property on the viewModel (Bert changed to Benny). But because it is just a string, and nobody knows that it has changed the first element still shows the old value(Bert) on the screen.

“Observables” to the rescue!

KO has the concept of "observables".

var viewModel={
    firstName: ko.observable("Bert")
};

If you declare that the firstName property is observable, the two way binding kicks into action and the span starts updating in sync with the data.

< p >First Name: < input data-bind="value: firstName" />< /p >
< p >First Name: < span data-bind="text: firstName" >< /span >< /p >

You can of course have multiple properties in a viewmodel.

var viewModel={
    firstName: ko.observable("Bert"),
    lastName: ko.observable("Smith")
};

You can also combine multiple bits of observable data. What if you want to display a person’s full name by joining the FirstName and LastName properties and the full name should update in sync with all the underlying data ?

Enter “dependent observables”

Let us define a full name property on the viewmodel.

viewModel.fullName =ko.dependentObservable(function(){
    return this.firstName() + " " + this.lastName();
}, viewModel)

What it basically means is that it is an observable (when it changes people get notified) but it also depends on other observables. You can use an arbitrary javascript function to return a value for the dependent observable. Notice that the properties are called as if they were functions. By doing this you read the latest value out.

Let us now display this on the UI.

< p >Full Name: < span data-bind="text:fullName" >< /span >< /p >

At this point, updating the first name will update the full name as well since KO is doing its dependency tracking thing. It knows that full name depends on both the firstName and the lastName and if either of those changes, the change propagates through the object graph and is pushed out into the user interface so that everything updates in sync with the underlying data model.

Let us move on to more sophisticated example and look at how you can add/remove DOM elements dynamically. When you want to generate blocks of HTML, often you would want to do it using templates since it is a nice, clean way of defining the markup that you want on the UI. What if you want track a list of friends this person has got?

Templating

We are going to do this the object oriented javascript way. We need a class that represents a friend. The friend constructor takes name and returns a new object that has a name property and the value will be an observable and its initial value will be the name passed to it.

function friend(name)
{
    return {
        name: ko.observable(name)
    };
}

Lets define an observable array of friends on the viewmodel. When you add/remove a new element people get notified that you modified it.

var viewModel={
    firstName: ko.observable("Bert"),
    lastName: ko.observable("Smith"),
    friends:ko.observableArray([new friend("Steve"), new friend("Jobs")])
};

We want to render the friends through a template. To render a template you use a binding called template and give the template a name.

    This will look for and render a template with this name (friendsTemplate). You need to define the template using a script block whose id is the name.

    < script id="friendsTemplate" >
    < ul>
        < li> $data.name </ li>
    < /ul>
    < /script >
    
    

    The list item is rendered once for each item in the friends observableArray. $data indicates for each friends.

    This will render all the friends on the page in a nice list (Steve and Jobs). What if you want to add more friends?

    <button data-bind="click addFriend:>Add friend</button>

    Bind the click event on the button to a function addFriend() and the function on the viewmodel that will handle this click.

    var viewModel={
        firstName : ko.observable("Bert"),
        lastName : ko.observable("Smith"),
        friends : ko.observableArray([new friend("Steve"), new friend("Jobs")]),
        addFriend : function(){
        this.friends.push(new friend("Joana"))
        }
    };
    

    When the button is clicked, addFriend() runs and pushes a new friend (Joana) into the observableArray friends. Since it is an observableArray and KO has dependency tracking, KO will re-render the template on the screen with the new friend included (Steve, Jobs and Joana). However the interesting thing to note is that re-rendering the template doesn’t mean re-rendering every element inside the template. The elements which were previously rendered are NOT being rendered again. KO knows the minimal set of changes that is necessary to get the user interface up to date.

    Conclusion

    At first I was wary of Knockout, because I worried that I would be adding too much logic to my Views (HTML). But working with it, it actually has made the code easier to maintain, since I can reason about how pieces of the views are generated by just looking at it, instead of having to read all of the JavaScript code to see what may be manipulating it.

    I hope you give Knockout a try!