Thursday, June 16, 2011

Knockout.js - cleaning up the client-side

I've started a new project with a client and it's quite a shift for me. Coming off a heavy client (WinForms), 3-year project I'm now working in ASP.NET MVC and javascript. One of my goals with regards to the architecture was to keep a handle on the javascript. The project is integrating with the ESRI ArcGIS Javascript API and so there will be lots of client-side javascript and it will be important to keep it organized and maintainable.

In looking around for javascript libraries to help with this I found Knockout.js. This is a library for building larger-scale web applications that use javascript more heavily.

Knockout works by extending the properties of your javascript models (basically a POJO... Plain Old Javascript Object). You can then bind your model to the view (HTML elements) by marking up the HTML elements using "knockout bindings" (there are quite a few to choose from and they're listed here). Basically a knockout binding is a way to bind a property on your model to a specific attribute of an HTML element. There are quite a few that come built into Knockout (including things like text, visible, css, click, etc).

Once you've got the view marked up you simply call
ko.applyBindings(model);
and Knockout takes it the rest of the way.

Let's walk through a simple example as that'll make things more clear (I'm going to use the same Login UI example as Derick Bailey used for his first Backbone.js post so it's a bit easier to compare apples-to-apples... hopefully).

The layout is very similar to a Backbone view except that in a Knockout view you add extra 'data-bind' attributes.



Notice the 'data-bind' attributes in the markup. These dictate how knockout will bind the model we provide to the UI. Let's move on to the model now.



This is very close to being a simple javascript object. The only trick is that any property that we want to bind to the UI should be initialized via the ko.observable() method. The value we pass to the ko.observable() will become the property's underlying value.

Once we've instantiated a model object we simply call ko.applyBindings() and Knockout does the rest. (Note that the second parameter is the HTML element that should be the root of the binding. It is optional if you are only binding one object to your page, but I think in almost any application you'll get to a point where you want to bind multiple objects so this shows how to do that.)

At this point Knockout will keep the UI and model in sync as we manipulate it. This is full 2-way binding for the text elements. So if the user types in the username field, the model's username property is updated. If we update the model's username property the UI will be updated as well.

Derick noted in his blog post the mixing of jQuery and Backbone.js. I'm doing some of that here, but I think Knockout.js doesn't need jQuery as much because of how the binding is declared (on the HTML elements themselves).

I'm going to try to follow Derick's excellent series of posts on Backbone.js and comment on how the subjects he discusses compare and contrast with Knockout.js.

In the end I think both are very capable libraries even if they come at the problem from slightly different angles. In the end it's all about better organization of javascript and better assignment of responsibilities in the javascript you write.

3 comments:

Derick Bailey said...

wow! that's certainly a lot more terse than the examples i showed for backbone. have to say i'm quite impressed with it knockout, from this example!

one of the things i've heard in the differences between KO and BB, is that KO works best with ASP.NET MVC, while BB works best with Rails. i don't think these statements are saying you can't do KO w/ Rails or BB w/ ASP.NET MVC; only that they were built with those back ends in mind, so they work easier with them.

have you heard anything like this? i keep trying to find sources that can confirm, deny, or clarify this, but haven't found much yet.


i'm definitely looking forward to see more posts about KO, though. keep me posted on what you write up. :)

Jeremy Wiebe said...

@Derick I haven't heard that about KO<->MVC and BB<->Rails. If you find anything, please share. :-) That said, I know that Knockout is written by Steve Sanderson who works for Microsoft on the ASP.NET team so that would explain things if KO was more "tuned" for MVC.

One thing I wonder about is the fact that Backbone has the concept of Controllers. Knockout doesn't have anything like that and I'm wondering if Knockout may fall down as an app gets larger. I guess I'll see. You post fast but I'll try to keep up. :-)

Anonymous said...

good job!
i would be nice if you could show us how you implemented KO and javascript api integration, espacially initialization of map components etc.
thanks