Exploring KnockoutJS - Part1: The Basics

The ever increasing sophistication of web applications has increased the need for coming up with strategies to make JavaScript code clean and maintainable.  JavaScript has become more of a first class citizen over recent years and requires the same sort of patterns and organization that so many server side technologies have adopted such as C# to provide elegant code.  One such pattern that emerged in recent days is the Model View View-Model (MVVM) pattern, which provides a separation of concerns between client side model and view data.  This pattern allows the view to bind to data in a declarative fashion, rather than using a direct programmatic approach.

Programmatic vs. Declarative


The Programmatic Approach with jQuery


Consider the following basic example using jQuery to programmatically set some values in html.  The script is manually setting each value of the contact object properties (name, address, phoneNumber) to the html elements designated by their id. 


1.  <script type="text/javascript" src="//code.jquery.com/jquery-2.1.0.min.js"></script>  
2.  <script type="text/javascript">  
3.      $(document).ready(function(){  
4.          var contact = {  
5.              name: "John Doe",  
6.              address: "1 Pebble Drive, Horsham PA 19044",  
7.              phoneNumber: "(215) 555-1212"  
8.          };  
9.    
10.         $('#name').text(contact.name);  
11.         $('#address').text(contact.address);  
12.         $('#phoneNumber').text(contact.phoneNumber);  
13.     });  

1.  <!DOCTYPE html>  
2.  <html>  
3.  <head lang="en">  
4.      <meta charset="UTF-8">  
5.      <title>Exploring KnockoutJS</title>  
6.  </head>  
7.  <body>  
8.      <h1>Exploring KnockoutJS</h1>  
9.    
10.     <div id="name"></div>  
11.     <div id="address"></div>  
12.     <div id="phoneNumber"></div>  
13. </body>  
14. </html>  


This approach is ok, but requires code changes when the data contract changes.  It also tightly couples the code to the view because the code is directly references elements of the user interface by their IDs.

The Declarative Approach with KockoutJS

(Note: the KnockoutJS library requires jQuery)

In the declarative approach, rather than manually binding data values using code, we’ll create a ViewModel and bind it to the view using KnockoutJS.  The data bindings will be specified on the HTML elements using the data-bind attribute, indicating to knockout what model property should be used for display.

1.  <script type="text/javascript" src="//code.jquery.com/jquery-2.1.0.min.js"></script>  
2.  <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>  
3.    
4.  <script type="text/javascript">  
5.    
6.      function ContactViewModel() {  
7.          this.name = "John Doe";  
8.          this.address = "1 Pebble Drive, Horsham PA 19044";  
9.          this.phoneNumber = "(215) 555-1212";  
10.     }  
11.   
12.     ko.applyBindings(new ContactViewModel())  
13.   
14. </script>  

1.  <!DOCTYPE html>  
2.  <html>  
3.  <head lang="en">  
4.      <meta charset="UTF-8">  
5.      <title>Exploring KnockoutJS</title>  
6.      <link rel="stylesheet" text="text/css" href="ExploringKnockout.css">  
7.  </head>  
8.  <body>  
9.      <h1>Exploring KnockoutJS</h1>  
10.   
11.     <div id="name" data-bind="text: name"></div>  
12.     <div id="address" data-bind="text: address"></div>  
13.     <div id="phoneNumber" data-bind="text: phoneNumber"></div>  
14. </body>  

This approach allows us to remove the code that is setting the value to a particular display element and rather just specify the binding tag in the view instead.  It seems fairly simple, but this is just the tip of iceberg as to what utilizing this framework can do.  We can also setup our code and bindings to notify us when properties change in editable user interface components so that we can take action, create programmatic control flow (if/else, loops, etc.), create reusable user interface templates and more.

Observables


One of the key elements of the KnockoutJS framework is an object type called an Observable.  Using an Observable object allows Knockout provide notifications when the value of an element changes so that action may be taken upon it.  In this example we’ll setup the interface to take the value of a text box and update a div element.

 

Simple Binding Example


So let’s setup a simple example using an observable property in a ViewModel.  It’ll have a single property called “name” that is bound to a div element which will display the text of an input box.

1.  <script type="text/javascript">  
2.    
3.      function ContactViewModel() {  
4.          this.name = ko.observable("Jane Doe");  
5.      }  
6.    
7.      ko.applyBindings(new ContactViewModel())  
8.    
9.  </script>  

Note that the data-bind value is setup to bind the name property of our ContactViewModel and the div element displaying it is binding the text.  As well, the initial value is set to “Jane Doe” so that we’ll see data as soon as the page loads. 

1.  <!DOCTYPE html>  
2.  <html>  
3.  <head lang="en">  
4.      <meta charset="UTF-8">  
5.      <title>Exploring KnockoutJS</title>  
6.      <link rel="stylesheet" text="text/css" href="ExploringKnockout.css">  
7.  </head>  
8.  <body>  
9.  <h1>Exploring KnockoutJS</h1>  
10.   
11.     <p>name: <input data-bind="value: name" /></p>  
12.   
13.     <div data-bind="text: name" ></div>  
14.   
15. </body>  
16. </html>  
17. <script type="text/javascript" src="//code.jquery.com/jquery-2.1.0.min.js"></script>  
18. <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>  


Resulting Output




Though this is a really simplistic example it starts to paint the picture of what KnockoutJS can provide.  It removed the need to manually retrieve the value of the text box once its content is changed and then manually set the value into element displaying it below.

Computed Observable Binding


Let’s take it one step further and now act on the bindings by computing a value from other values in the model.  In this example we’ll just expand the example above a bit by adding a couple more fields and then displaying the data from them on a single line with a computed observable value binding.


1.  <script type="text/javascript" src="//code.jquery.com/jquery-2.1.0.min.js"></script>  
2.  <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>  
3.    
4.  <script type="text/javascript">  
5.    
6.      function ContactViewModel() {  
7.          this.name = ko.observable("");  
8.          this.address = ko.observable("");  
9.          this.phone = ko.observable("");  
10.   
11.         this.contactSummary = ko.computed(function() {  
12.             return this.name() + ", " + this.address() + ", " + this.phone()  
13.         }, this);  
14.     }  
15.   
16.     ko.applyBindings(new ContactViewModel())  
17.   
18. </script>  

In the snippet of script above note the use of the computed property of ContactViewModel called “contactSummary.”  It’s a function of the model that utilizes the other property values and returns the output of the function in the resulting data binding.

1.  <!DOCTYPE html>  
2.  <html>  
3.  <head lang="en">  
4.      <meta charset="UTF-8">  
5.      <title>Exploring KnockoutJS</title>  
6.      <link rel="stylesheet" text="text/css" href="ExploringKnockout.css">  
7.  </head>  
8.  <body>  
9.  <h1>Exploring KnockoutJS</h1>  
10.   
11.     <p>name: <input data-bind="value: name" /></p>  
12.     <p>address: <input data-bind="value: address" /></p>  
13.     <p>phone: <input data-bind="value: phone" /></p>  
14.   
15.     <div data-bind="text: contactSummary" ></div>  
16.   
17. </body>  
18. </html>  

The html is essentially the same, there’s no difference in binding to an observable whether it’s computer or not.

Resulting Output











The output shows how the computed observable took each of the other bound values and concatenated them separated by commas.  Again, this is a pretty basic example of what you can do but it illustrates the concept that you can provide functionality to manipulate an observed property which is a power feature of the framework.


More to come…


I explored some of the basic concepts of KnockoutJS, though there are quite a few more features available including the ability to define element templates to create reusable chunks of UI elements that include programmatic control flow.  In the next entry I’ll explore a bit deeper and check out some of the more powerful functionality of the framework.

Labels: , , ,