Mobile (and desktop) HTML5 applications are commonly written with an MVC framework such as Sencha Touch or a custom Backbone implementation. The MVC architecture is also wildly popular for server frameworks like Ruby on Rails. Developers are familiar with the trappings of MVC, and generally feel comfortable with MVC’s paradigms and conventions. Indeed, MVC is a great architecture for many frameworks and applications. However, when developing for mobile, MVC is often not the best choice. Mobile apps have the somewhat unique requirement that they be very responsive to user interaction, which means using a lightweight framework and optimizing for as few steps as possible between the interface and the business logic. The applications themselves are often not of the greatest complexity, but rather offer a subset or a simplified set of features from an existing product, or are designed to be quickly and easily used. Mobile apps also often rely heavily on web services and the data that they provide, meaning a heavy reliance on data models and populating views with varying data. All these factors boil down into not needing a large framework, needing a framework to get things up and running quickly and to stay quick, and needing a framework with excellent data to view binding abilities. In my opinion, frameworks that employ the MVVM architecture are better choices for the above set of conclusions.
So, what is MVVM and how is it different from the old standby MVC that we all know and love? For starters, MVVM stands for Model, View, and ViewModel. Model and View are the same as in MVC: models are used to hold and describe data, and views are used to display content. The view model, however, is the piece of the puzzle that differs. The view model acts as a mediator between the view and the model, essentially providing a map between the data and the presentation, and in many cases is an active binder between the two (see Knockout below). The view model takes the place of the controller in most MVC frameworks, wherein the controller would be responsible for mapping data between the view and the model (usually in an ad-hoc fashion, directly accessing and manipulating view components).
With the basics out of the way, let’s discuss a specific implementation of MVVM suitable for mobile HTML5 applications. One such implementation is the Knockout open source project by Steve Sanders. From the Knockout website: “Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model.” Knockout is made to integrate well with other frameworks and libraries, and many developers use it with plain jQuery or jQuery Mobile to great effect. Knockout, however, is not an end to end framework: it does not provide an HTTP request library, storage, or any of the myriad features of a larger framework like Sencha Touch. This, however, can sometimes be a great thing. All applications do not need all features of a large framework, and can usually get by with a small set of libraries like Knockout, jQuery Mobile, and any miscellaneous libraries they might need for persistence, hardware integration, etc. By starting small, we also already have a performance advantage.
Knockout is very easy to get up and running. Let’s start making a simple web page by pasting the below into an HTML file:
<!DOCTYPE html> <html> <head> <!-- Include Knockout --> <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script> </head> <body> <!-- This is the view --> <p>X: <strong data-bind="text: x"></strong></p> <p>Y: <strong data-bind="text: y"></strong></p> <script type="text/javascript"> // This is the view model function ViewModel() { this.x = '42'; this.y = '24'; } ko.applyBindings(new ViewModel()); </script> </body> </html>
At this stage, if you load the file into a browser, you should get the values of X and Y substituted into the view. Not very exciting, but a few key concepts are illustrated here. First: HTML is your view, and you define special “data-bind” attributes to reference which value from the view model gets placed into the tag’s content. Second: that your view model is a very simple JS object that gets applied to the view using Knockout. Let’s make the data editable by adding some input fields:
<!DOCTYPE html> <html> <head> <!-- Include Knockout --> <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script> </head> <body> <!-- This is the view --> <p>X: <strong data-bind="text: x"></strong></p> <p>Y: <strong data-bind="text: y"></strong></p> <p>X: <input data-bind="value: x" /></p> <p>Y: <input data-bind="value: y" /></p> <script type="text/javascript"> // This is the view model function ViewModel() { this.x = ko.observable('42'); this.y = ko.observable('24'); } ko.applyBindings(new ViewModel()); </script> </body> </html>
Now that we have added two input fields and bound the value attribute, after you edit an input field and blur it, the value change is propagated to all other bound view elements. We do this by changing our view model properties to be observable, and by binding the input field value attribute to the view model. Making the view model properties observable now means that Knockout tracks changes to them and propagates changes to everything that depends on their values (currently, the display and input fields).
Another key concept with Knockout – and the last in this introduction – is computed values. Computed values can depend on other view model attributes, and are intelligently updated when any dependent view model changes.
<!DOCTYPE html> <html> <head> <!-- Include Knockout --> <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script> </head> <body> <!-- This is the view --> <p>X: <strong data-bind="text: x"></strong></p> <p>Y: <strong data-bind="text: y"></strong></p> <p>SUM: <strong data-bind="text: sum"></strong></p> <p>X: <input data-bind="value: x" /></p> <p>Y: <input data-bind="value: y" /></p> <script type="text/javascript"> // This is the view model function ViewModel() { this.x = ko.observable('42'); this.y = ko.observable('24'); this.sum = ko.computed(function() { return parseFloat(this.x()) + parseFloat(this.y()); }, this); } ko.applyBindings(new ViewModel()); </script> </body> </html>
Now, when we change an input field value, the sum display also changes. The sum attribute is defined in the view model using a ko.computed function that returns the sum of the two values contained in the x and y attributes. Knockout now knows there’s a dependency between sum and the x and y attributes, and when x or y is updated, it also propagates the change to the sum computed attribute. Note that, in order to get the value of the x and y attributes, we call them as functions. Similarly, if we wanted to set the value of a field, we would call the attribute function and pass it the new value.
So, that’s Knockout and MVVM in a nutshell. Hopefully the power, simplicity, and elegance of Knockout is evident in the few short examples above. In future posts, I’ll discuss more advanced Knockout features like handling button actions, conditionally hiding and showing view elements, and how to make use of Knockout for mobile applications.
That’s why I love Knockout, it is very simple. I was looking for a way to use the Knockout for mobile applications and found your article. Liked, I read the other parts.