Saturday, December 29, 2012

Architecting KnockoutJS Applications

One of my favorite front end javascript libraries is KnockoutJS.

KnockoutJS is a javascript library that helps you bind javascript variables to DOM data. When you change the javascript variable the HTML automatically changes to the new value of the variable.

The magic behind how this happens isn't particularly important. If you really want to know you can read the source. The basic pattern is commonly referred to as event pooling.

Some of the best parts:

 - You should use knockout if you have a bunch of $(element).click(function()) functions and want to clean it up. If your frontend code is even a bit complicated you probably know what I am talking about.
 - It is easy to integrate with an existing project. AngularJS is probably best off when you are starting from scratch. Knockout is great because you can optionally use it when you have a really complicated frontend.
 - Really quick to learn. I found knockout super easy to pick up. The thing you have to get over is your elements looking like:

<span data-bind="text: airplane"></span>


It irked me a bit to see a data-bind attribute when it isn't really HTML. Yes you are mixing presentation logic with code. Honestly though I've seen learned that it is pretty pragmatic. Lots of HTML editors play nice with knockout and people who only know HTML and CSS can pick it up quickly.


Some of the parts I don't particular like about Knockout:

 - Lack of a good PJAX/history.js style navigation. You get this with AngularJS.
 - Getting your view models to be semi reusable is a pain in the butt. I used a combination of server side script includes and knockout statements.

When first getting started you may wonder how should you architect your application so it is somewhat less like spaghetti. A good way to organize your Knockout code is first think of all the objects in your application. If you are using Rails (or in my case Django) you will have a bunch of models.

For each of these models it is nice to have some sort of front end analogue in Javascript.

Here is an example of an object:


function Airplane(viewModel, data) {
  var self = this;
  ko.mapping.fromJS(data, {}, self);

  self.visible = ko.observable(true);
  self.selected = ko.observable(false);

  self.land = function(item, event) {
    $.ajax({
      url: "/api/airplane/" + self.id() + "/land",
      type: 'POST',
      success: function() {
        // Update myself with the fresh data from the server
        ko.mapping.fromJS(data, self);
      },
      error: function(jqXHR, textStatus, errorThrown) {
      }
    });
  }
}

I usually like to stick this in some namespace that is available globally. A few comments about this object. I take in the viewModel which created it so I have access to the parent (this is useful later). I also take in this variable called data which is used for an awesome knockoutjs plugin called ko.mapping. It basically iterates through your javascript object and creates ko.obserables() out of all of attributes. Super useful and you want to use this. I didn't use it before and I had to do self.variable = ko.observable(data.variable) over and over. Yeah not a good idea.

Another awesome thing about the plugin is when your AJAX REST API call returns you can update the object in one line by doing ko.mapping.fromJS(data, self).

Hope you give knockout a try. If you have any questions I've noticed the knockout community is awesome. I am also available so just drop me a note.

-Jeff