Knockout

by Dave Sweeton

A while ago I saw some demos on model binding frameworks written in JavaScript for client-side use. They seemed to have a lot of potential, and after reviewing some of the leading contenders (Angular JS, Backbone.JS, Knockout) I settled on Knockout. My exact reasons for choosing Knockout are lost in the fog of memory; all of these frameworks are mature and capable, though they all work differently. I suspect Knockout just seemed to fit my needs better or was easier to spin up with. I started dipping my toes into the water with small and isolated usages in existing projects, and have built up to more and more complex solutions.

What Is It?

Knockout is essentially about model binding and templating. You have some objects that represent your data (the "model"), and you have controls that edit that data and other elements that dynamically display data. What Knockout does is magically track which elements are using the data—and update them automatically when the model changes. You have to set up your model using some special method calls, but after that the dependency tracking is fully automatic, even with deep object hierarchies. Here’s what I like about Knockout:

  • Defining the models is pretty easy, with not too much extraneous junk.
  • The model binding syntax (and templating) is done in your HTML, and it’s pretty clean.
  • Dependency tracking really is magic in the best sense of the word. Things just update when they should.
  • Knockout itself is minimally invasive, and can be mixed in with other libraries and used on existing projects easily.
  • The core Knockout functionality covers a lot of use cases, including binding to events. When you run into cases that are above and beyond, you can find or write extensions to the core library. There’s an extra learning curve to writing extensions, but it’s do-able.

A small sample

Let’s see a sample of Knockout in action. I’ve omitted everything boring like script includes and wrapping HTML.
Here’s a model defined in JavaScript:

function Model() {
 var self = this; //capture it
 self.Name = ko.observable();
 self.IsDave = ko.computed(function(){
  return self.Name() === "Dave";
 });
}

This defines a simple object that represents the model. The model has a property Name, an instance of a Knockout observable, which is part of the glue that makes the dependency tracking work. The model also has a computed boolean property IsDave, which is true if the name property is "Dave." This property will be magically re-evaluated every time the value of the Name property changes.
Here’s the HTML content:

<p>What's your name?
 <input type="text" data-bind="value: Name"/>
</p>
<p>Your name is
 <span data-bind="text: Name"></span>.
</p>
<p data-bind="visible: IsDave">
 Hi Dave!
</p>

This is all standard HTML5, but the data-bind attributes are what the Knockout library uses to wire things up. The textbox has its value bound to the Name property of the model. This is a fully two-way binding. When the user types a new value in the textbox, the model’s value will be updated, and if something else changes the model (like a second textbox or dynamic code), the textbox will show the new value. The span in the second paragraph works similarly, but it’s a display-only element. Anytime the model value of Name changes, it will show the new value.
The third paragraph is either hidden or shown based on whether the IsDave model value is true or false, and once again this is fully automatic.
The last thing you need to make this work is to create the model and pass it to the Knockout library, like so:

ko.applyBindings(new Model());

That’s a pretty contrived example, but it shows how simple and clean the Knockout markup is.

Building complexity

In addition to observables and computeds, there’s one other building block, ko.observableArray(). This simply creates an array-like object that tracks when items are added or removed. It can be used to show lists like so:

<ul data-bind="foreach: Users">
 <li data-bind="text: Name"/>
</ul>

Conditional formatting can be done using the if binding, which adds or removes content from the document (unlike visible, which just controls its visibility using styling). You can also use containerless syntax if you don’t want to (or can’t) change your markup:

<!-- ko if: IsDave -->
This content won’t exist if false.
<!-- /ko -->

There are plenty of other useful bindings too, like ones for setting CSS styling, wiring up other controls like checkboxes and select lists, or for the click events of buttons.

Further Applications

I’ve successfully used Knockout for complex scenarios where I’m showing the user a lot of data items, and giving them the ability to arbitrarily group them, calculate sums or averages, change sort order or filter the display to remove items. In the past I would’ve implemented something like that with a post back to the server for each and every change. Server-side implementation was convenient, but redundant because I’d be sending down different views of the same data over and over. Implementing the model on the client-side takes some extra effort, but it vastly improves the feel and performance of the application.

I’ve also used Knockout for a "single page" application that had a large number of formatted and validated input fields (some which were used conditionally based on other inputs). These inputs were passed to the server via AJAX when they changed (but only if they were valid), and the server returned a lot of data which was mapped back into the model and displayed in a variety of different formats.

Knockout brings its own cognitive and maintenance overhead, but I’ve been very pleased at how simple and automatic it makes some complex scenarios.

Find out more about Knockout at: http://www.knockoutjs.com/

See more tutorials at: http://code.tutsplus.com/

info@stoutsystems.com
877.663.0877
© Copyright 1995-2022 - STOUT SYSTEMS DEVELOPMENT INC. - All Rights Reserved
envelopephone-handsetlaptop linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram