LearnBuild Dynamic Pages with Knockout.js

Treehouse
writes on June 14, 2011

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!

22 Responses to “Build Dynamic Pages with Knockout.js”

  1. “The View, however, is written in HTML, utilizing HTML5 data attributes
    to define metadata.”

    Before I’m giving Knockout a try, I wonder if the use of HTML5 is causing any trouble in Internet Explorer (8 or 9)? As far as I know, it’s still not fully supported by IE (i’m not using IE, but our clients do) Does anyone experienced any problems with this?

  2. “The View, however, is written in HTML, utilizing HTML5 data attributes
    to define metadata.”

    Before I’m giving Knockout a try, I wonder if the use of HTML5 is causing any trouble in Internet Explorer (8 or 9)? As far as I know, it’s still not fully supported by IE (i’m not using IE, but our clients do) Does anyone experienced any problems with this?

  3. I must say JS starts to have more or more complex features thanks to libraries like that. Of course the drawback is that you will need to download loads of JS libraries, learn them, and yet use them. Advantage is that code which was written for a single page now can be reused… Quiet impressive overall.

  4. I must say JS starts to have more or more complex features thanks to libraries like that. Of course the drawback is that you will need to download loads of JS libraries, learn them, and yet use them. Advantage is that code which was written for a single page now can be reused… Quiet impressive overall.

  5. I don’t really see the breakthrough here, although it does look like a cool script. I also think that it’s cool that it’s tailored for HTML5 specifically (right?).

    But I also think a jQuery/Handlebars.js combination would do much better in terms of… everything. You have the controller and model built with jQuery and the View with Handelbars. Also, it’s cool as with a bit of effort you can get Handlebars.js templates to be compatible with Smarty templates and then probably you’d have the Model requesting data from a PHP script. As it all ties together, you can decide at any point that you want some data to load with Ajax and what not, making life easier for everyone. (I don’t do Ruby, but for whoever does Ruby it’s even better as Mustache templates are already compatible afaik)

    Nice find anyway, I think it’s great but only for a small category of web apps (thinking mobile here)

  6. I don’t really see the breakthrough here, although it does look like a cool script. I also think that it’s cool that it’s tailored for HTML5 specifically (right?).

    But I also think a jQuery/Handlebars.js combination would do much better in terms of… everything. You have the controller and model built with jQuery and the View with Handelbars. Also, it’s cool as with a bit of effort you can get Handlebars.js templates to be compatible with Smarty templates and then probably you’d have the Model requesting data from a PHP script. As it all ties together, you can decide at any point that you want some data to load with Ajax and what not, making life easier for everyone. (I don’t do Ruby, but for whoever does Ruby it’s even better as Mustache templates are already compatible afaik)

    Nice find anyway, I think it’s great but only for a small category of web apps (thinking mobile here)

    • I’m in no way suggesting you throw out everything and instead use Knockout. That’s crazy. If you do take the time to check out what Knockout can do you will have another tool in your toolbox, and a new way to think about solving problems. It’s not good to be too dismissive of new technologies in favor of what you already know.

      Knockout doesn’t replace jQuery, and templates like handlebars. In fact the default templating support built into knockout relies on jquery.tmpl. Who knows, someone could create a handlebars.js adapter for Knockout templates. I seem to remember someone around here being a core contributor for handlebars.js.

      I’ll be writing more about Knockout, there’s a lot of cool things that can be done with it. As an experiment, I rewrote the Backbone code from my HTML5 Masterclass using Knockout, and the resulting code was about 25% the size of the original code, and much easier to follow. It’s a very cool, and underutilized tool.

      • Those are some very interesting insights, looking forward to your next articles on Knockout and, as you said, the more tools out there, the merrier, especially as the learning curve is very steep and you can use them in projects in no time.

  7. Too many tools out there, pure js, jquery, mootools, backbone, extjs, now knockout, did u guy manage to learn all and use it in daily work???

    • It’s worth trying a new tool whenever you have an idea for a side project. I don’t use every tool I know every day, but having a large selection of tools to use is extremely advantageous. 

  8. Too many tools out there, pure js, jquery, mootools, backbone, extjs, now knockout, did u guy manage to learn all and use it in daily work???

    • It’s worth trying a new tool whenever you have an idea for a side project. I don’t use every tool I know every day, but having a large selection of tools to use is extremely advantageous. 

  9. It solves the wrong problem, I think. When you request the document from the server, the markup you get back is useless as it contains only boilerplate and is missing all the actual content.

    • That’s fine for applications as you don’t need any markup. For a website tho this would be a concern due to the fact a search engine wont make these connections. Except, of course, if you ran this via Node…

    • Sirtimbly on June 14, 2011 at 5:09 pm said:

      It’s a useful tool if you are trying to build a web app in a very specific way. No refreshes, live data updates in an interface. Its a hard balance to design for, but I can see this tool being valid for some applications. As always you have to balance the desire to use the latest and greatest with everything else.

    • It solves a different problem than you are thinking of. For content based websites, I wouldn’t use it, because the information and markup is important.

      When you start building things like single page applications, and you are streaming in tweets, and manipulating a lot of data, the markup sent on the initial page load isn’t important, since it’s really just the foundation for an application, not information itself.

  10. It solves the wrong problem, I think. When you request the document from the server, the markup you get back is useless as it contains only boilerplate and is missing all the actual content.

    • That’s fine for applications as you don’t need any markup. For a website tho this would be a concern due to the fact a search engine wont make these connections. Except, of course, if you ran this via Node…

    • It solves a different problem than you are thinking of. For content based websites, I wouldn’t use it, because the information and markup is important.

      When you start building things like single page applications, and you are streaming in tweets, and manipulating a lot of data, the markup sent on the initial page load isn’t important, since it’s really just the foundation for an application, not information itself.

  11. It’s great that ThinkVitamin finally gave some attention to Knockout.js, I hope this article doesn’t stop here, there is a lot of ground to be covered when you adopt the amazing MVVM approach.

    You can check out some nice stuff here:
    http://www.knockmeout.net

    Also some of my experiments on github:
    http://github.com/thelinuxlich

    • This won’t be the last article. What I really want to cover is so much longer than I could fit into a post, so in the future we will look at some more advanced features of Knockout, and even how you can extend it.

  12. It’s great that ThinkVitamin finally gave some attention to Knockout.js, I hope this article doesn’t stop here, there is a lot of ground to be covered when you adopt the amazing MVVM approach.

    You can check out some nice stuff here:
    http://www.knockmeout.net

    Also some of my experiments on github:
    http://github.com/thelinuxlich

Leave a Reply

You must be logged in to post a comment.

Want to learn more about Javascript?

Learn how to use JavaScript to add interactivity to websites.

Learn more