Site icon Treehouse Blog

Build Dynamic Pages with Knockout.js

Building dynamic web pages using JavaScript can be a complex task. Fortunately, frameworks like jQuery, MooTools, and others make it much easier to interact with the browser. However DOM frameworks only solve part of the problem.

When building an application that has a lot of data that can be updated, and any piece of information could be represented in several places on the page, it becomes a pain to try to make sure the interface accurately represents the data at any point in time.

There are heavy duty application frameworks that can take care of this problem like SproutCore, Cappuccino, and ExtJS. These tools have a steep learning curve, and can be inconvenient to integrate into an existing project.

Lightweight tools like Backbone and Spine offer solutions that are easier to pick up. You can watch my Master Class on creating an application with Backbone.js and jQuery Mobile on Think Vitamin Membership.

The MVC Solution

All of these tools utilize a similar pattern for solving the data consistency problem, Model-View-Controller or MVC.
Put simply you write some JavaScript to represent your data (Model), some JavaScript to store and handle changes to that data (Controller), and some JavaScript to render the HTML representation of the data (View). All in all, it turns out to be a lot of code to write.

The MVVC Solution

Knockout.js offers a different pattern: MVVC, or Model-View-ViewController. In Knockout you still create a Model in JavaScript to represent your data. The View, however, is written in HTML, utilizing HTML5 data attributes to define metadata. Then a ViewController defines what data is presented to the View.

Let’s take a look at a very simple example.

HTML:

My name is
<span data-bind="text: name"></span>

JavaScript:

var viewController = {
  name: "Jim"
}

ko.applyBindings(viewController)

Run this code

In this example we create a View in HTML. We give the span a data-bind attribute specifying its text contents should be determined by name.

In the JavaScript we create a simple ViewController as a normal JavaScript Object, and define that name should have the value "Jim". In this example the string "Jim" is a Model, though a Model could be a more complex object.

When we call ko.applyBindings() and pass it the viewController. Knockout wires up the View (HTML) to the ViewController (JavaScript), and ensures that it sets the text of our span to the value of name in the ViewController.

Observables

Our first example showed how Knockout can do a simple static text substitution, but what would happen if we called the JavaScript code viewController.name = "Nick"; ?

The ViewController would have an updated Model, but our HTML View would not change to reflect the name. This is because there is no way for Knockout to directly be notified that the data in the ViewController has changed.

Knockout provides a special object called an Observable that solves this problem. An observable wraps a value, or Model, and when you change its value, Knockout notifies all Views (and other code interested in that value) that it has changed. This way our View can update itself with the new value.

Let’s look at an example of how to use an Observable

HTML:

My name is
<span data-bind="text: name"></span>

JavaScript:

var viewController = {
  name: ko.observable("Jim")
}

setTimeout(function () {
  viewController.name("Nick");
}, 2000);

ko.applyBindings(viewController);

Run this code

The View Code is the same. However, in the viewController object, instead of assigning a string to the key name, we instead use ko.observable("Jim"). This is how we create an Observable object. When we create it, we can pass an optional initial value, in this example "Jim".

To access and change the value of an observable object, we need to treat it as a function. If we were to call viewController.name(), it would return the current name. To set the value, we pass it a new value viewController.name("Nick"). This will change the value, and notify the View that it has changed.

In this example, we set a timeout so that in 2 seconds, we will update the viewController.name, and the view is updated automatically to display “Nick”.

Bindings

So how does the View know to watch the name value, and how does it know what to do when it changes?

The View uses bindings, which are defined in the data-bind attribute of an HTML element. The syntax is similar to JSON, and takes the form key: value, key: value. A key is a type of binding, of which there are many built in; text: represents the text content of a tag, value: the value of a form input, etc… You can view the different available bindings at the documentation.

The value of a binding is either a literal JavaScript value, like a string or number, or it can be an expression. If the expression is the name of an key in the ViewController, knockout will determine which Observable is used to determine the value, and will watch it for changes. When the Observable signals it has changed, Knockout evaluates the current value, and updates the view.

There’s More

This first part only scratches the surface of what Knockout is capable of doing. In upcoming posts I’ll show you how to create dependent observables, and create more advanced interfaces with Knockout.

Knockout is a great tool to keep in your toolbox because it solves a common problem in a different way than most other tools.

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!

Exit mobile version