JavaScript Frameworks | How to Learn Them Quickly

The key to quickly learning JavaScript MV* Frameworks is to break them down into a series of features. The main features of an MV* application are routing, data binding, templates/views, models, and data storage. In this post I’ll describe these main features and show code examples from two or three frameworks for each feature. You will begin to concretely understand what these frameworks are trying to help you accomplish and realize they are more alike than they are different. In fact, it becomes apparent that most of the frameworks borrow heavily from the successes of the others.

I tend to see the similarities in people and not the differences.  Isabel Allende

Don’t be too concerned about understanding every line of code. For now, try to appreciate how similar they are and the problems they can solve for your project.

Routing

Routing, at a minimum maps your URLs to actions, but sometimes goes as far as implementing a full “state machine” design pattern for managing state transitions within a view.

If you’ve ever using the router in a server-side MVC framework such as Rails, CodeIgniter, CakePHP, ASP.NET MVC, Spring MVC, JSF, STRUTS, Grails, etc… then you can just think of the JavaScript MV* routers as the same thing but running on the client in JavaScript and routing to other JavaScript objects instead of running on the server and routing to server-side code written in PHP, Ruby, Java, C#, etc..

So you may be wondering how can this work and will this work on older browsers? It works by default by using everything after the hash tag in a URL as the route, however, if HTML push-state support is configured (with one line of code in most frameworks) then URLs without hashes that match the routes will be intercepted on the client and run JavaScript as well.

Push-state is NOT supported by default because URLs directly requested via bookmarks or sent in an email will work for the end user but search-engine crawlers do not have great support for JavaScript, I.e., they may not run the JavaScript code and subsequently won’t see the correct content on the page. The generally proposed solution to this is to run PhantomJS or another lightweight browser on the server and have it load the pages and JavaScript and return the generated markup and JavaScript. This takes some work to set-up, hence the default to the hash URLs that all browsers support.

Enough details let’s see some code.

Backbone Example

Here is a simple example of routing in Backbone.js

In particular notice the AppRouter object. Routes are mapped to functions. The functions simply create a view object which manages a DOM fragment and add it to the page when the URL changes. The Backbone.history.start() tells Backbone to start listening for URL changes.

AngularJS Example

Here is a simple example of routing in AngularJS.

The AngularJS example is very similar to the Backbone example except routes map to templateUrl’s and controller classes (controllers are similar to Backbone’s views in this usage).

Ember Example

Below is a simple example of routing in Ember.

Again, very similar to the others except with Ember.js the first parameter to the router’s “resource” object is a routeName and the second is the URL. The order of these parameters confused me at first until someone pointed out that the path parameter is optional and frequently can be set by convention as it is with the about page in the example. Also, templates are required to make this simple routing example work but I’ll go over them in a later section. For now it’s enough to know the templates get placed in the {{outlet}}. It’s worth noting Ember’s router allows advanced features such as nesting of templates but here I’m just trying to show how similar in functionality it is to the other libraries.

Just the Routing

Most frameworks include a routing solution but Knockout.js focuses on data binding as discussed previously and recommends a best of breed solution with one of the JavaScript libraries whose only feature is routing. Common single-purpose libraries used for routing include SammyJS and HistoryJS. In summary, SammyJS works with browsers that support HTML5 History API as well as URL hashes for back level browsers (IE 8 and lower) . HistoryJS is smaller but only supports the HTML5 History API .

Data binding

Data binding allows changes in the model data to be updated in the view and/or changes in the view to be automatically updated in the model without additional code. One-way data binding generally indicates changes to the model are propagated to the view. Two-way data binding adds the ability for view changes to immediately be shown on the model. Data binding eliminates a lot of boilerplate code developers write and frees the developer to focus on the unique problems in the application.

AngularJS Example

Below is a simple example of two-way data binding in AngularJS. Typing in the input field will show the entered text after the welcome message.

KnockoutJS Example

KnockoutJS really just focuses on data binding and is used as part of a best of breed solution with other frameworks and libraries such as DurandalJS for screen management and composition and History.js or Sammy.js to handle the routing. Here is an example of data binding in KnockoutJS.

Backbone Example

Backbone doesn’t have automatic data-binding but it is possible to do manually. In practice, I’ve found one-way data-binding which updates the view when changes are made to the model to be extremely useful. Data-binding from the view to the model real-world use cases are less common (for example, you want a live preview of how text will look as the user types text in an editor). It can be helpful to have binding from the view to the model but frequently the view change is initiated from user input and you want to do other logic before or in addition to actually changing the model. For example, validating input before changing or filtering a list in addition to remembering the current filter. Below is a simple example where code has been implemented to bind both ways.

In summary, you listen for a change event on the model and call the view’s render property to get the model to update the view. Similarly, you listen for “keyup” on an input and change the model by getting the value out of the input with jQuery and setting it on the model to have the view update the model. This example should give you a feel for how much code it takes to get data binding working. It is also worth noting that there are numerous plug-ins that add support for data binding to Backbone.

Ember Example

Data binding in Ember looks like this:

Ember uses the familiar handlebars for templating but the framework also includes “input helpers” to bind common form input fields. The curly braces {{ replace the angle brackets < on the input in this example and the “name” property has no quotes so the helper knows to bind it. Ember does support two-way binding with very little code similar to AngularJS.

Templates/Views

Templates can be entire pages of HTML but more commonly are smaller fragments of HTML with data binding placeholder expressions included for dynamic data. They can be logic-less with the philosophy that there should be little to no logic in your views or some allow you to embed JavaScript directly in the template. Templates can be DOM-based and use the DOM to dynamically insert dynamic data or string-based treating the HTML as strings and replacing the dynamic parts.

Template Libraries

Libraries that help with templating include Handlebars.js which is the most popular one. Handlebars.js is frequently used with Backbone.js and included as part of EmberJS (Other template libraries can be used with Ember.js but you lose a lot of productivity and it’s not recommended). Mustache.js is another popular templating engine. UnderscoreJS is a dependency of the BackboneJS framework and is a utility library with a templating library as well as lots of functional programming stuff.  Dust.js is the rising star in this space being recently chosen by LinkedIn for use in their applications.  Handlebars.js and Mustache.js are also frequently used in applications with just jQuery and AJAX (no JavaScript MVC) when developers realize they need templating on the client. JQuery was working on it’s own templating library but it has been deprecated and I would not recommend using it.

Origins of Underscore

The back story is Jeremy Ashkenas, the creator of BackboneJS, extracted UnderscoreJS out of the original versions of Backbone so that the useful utility stuff could be used by people who were not using BackboneJS.

Lets look at some examples.

AngularJS Example

Here is a simple templates example in AngularJS.

You’ll notice this is very similar to the earlier routing example with some data binding added to show templates can help in your application. Templates are all included in script tags in the main HTML file to make the example easy to follow and work in jsfiddle.net but templates can be external to the view in AngularJS by simply giving a valid file path to the templateUrl property when configuring the $routeProvider.

It’s worth mentioning that the preferred way of handling templates in larger scale applications where performance is a concern is to concatenate and register your AngularJS templates in the Angular $templateCache at compile time with a build task such as this one

Ember Example

Below is an example of templates in Ember.

An Ember route is an object that tells the template which model it should display..not a URL. I think of it as the most basic controller for your template and resource (URL) whose main job is to load the model. If you need to get fancy and store application state then you need a controller.

Ember and AngularJS do use different implementations of templating: string based and DOM based templates respectively but they are trying to solve the same problems. Furthermore, the interfaces and contracts they surface to the developer are very similar. More specifically, they both use handlebars syntax to do bindings and script tags or separate files to store the templates.

Backbone Example

Now, lets look at a simple example of templates in Backbone.

This is a modification of the routing example but instead of the HTML being hard-coded in the the view object’s template property the markup is now in the HTML page inside a script tag with an id attribute (browsers ignore script tags with types they do not recognize such as text/template so the template won’t be shown). To get the template (HTML fragment) we use a jQuery selector to find the element by the script tag’s id and grab the innerHTML and then assign the HTML to the template property of the view object (it’s just a string).

Given this approach of treating templates as strings of html it’s easy to imagine how a different template library can be substituted in a Backbone application by simply implementing the template property slightly differently.

For example to use the Handlebars templating library instead of Underscore’s templating library we would update the view’s template property as follows:

template: Handlebars.compile( $("#home-template").html() ),

…and then update the binding syntax used in the templates for example
{{greeting}}

With these few minor changes we have changed out the template library used in the application.

Here is the full example with handlebars.js used for the templates.

It’s hard to draw the line between where some of these concepts end and the next ones start. In the case of templates when many people talk about templates they get into the templating libraries performance which has a lot to do with data binding previously discussed but also includes how the templates are loaded (are they precompiled into JavaScript etc…). To add to the confusion, templates are basically HTML as mentioned before and many server-side MVC developers associate HTML with the term views or partials. However, views in Backbone are code, a JavaScript class that manages an HTML fragment, and generally don’t have much markup in them except a reference to a template which is generally external to the view object.

Models

Models are the client-side version of what is commonly referred to as business objects, domain objects, or entities. As described by Jeremy Ashkenas, Backbone author, “models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control”. Ashkenas has been careful to say these are not going to be a one-to-one mapping with your Active Record models on the server but a smaller collection of them on the client with additional properties that are useful to the user interface such as a count. In general, the idea behind models in client-side MV* frameworks is to establish a central point for the data in the application as well as any behavior that should be encapsulated with that data. This model can be contrasted with server-side MVC plus jQuery architectures where the model data is commonly stored in the DOM. By having a model the goal is remove that data and state from the DOM and put it in a common place where it can be reused.

Backbone Example

Our earlier example of data-binding showed off models. In summary, models hold data and keep it out of the DOM and emit events such as “change” which allows numerous views to react accordingly and update the user interface everywhere it is needed. So now you have one source of the truth and it’s not the user interface.

I’ve modified the data binding example from earlier by adding a new template and view that looks at the same Person model object. Previously, I declared the Person model on the fly to keep things simple but now I’ve added the call to Backbone.Model.extend() method to demonstrate how you create a prototype for a model that can be used over and over similar to classes in classical languages. Notice how both views are listening to the same person model object (the change event) and updating themselves. By having this single source of data the numerous calls to specific DOM elements can be encapsulated in their own tidy views and one model can serve them all.

Notice how the get and set accessors need to be used for the change event to be fired in the example above…it is not uncommon to forget this convention.

AngularJS Example

The idea of one model that is the truth about the “state’” in your application exists in AngularJS but Angular allows you to use plain old JavaScript objects as your model and then adds watchers “under the hood” to any property that is added to the $scope object and declaratively data bound in the view with the directive “ng-model.” These watchers then automatically alert other parts of the application that are bound to that same model and these DOM elements know how to update themselves. So there is a lot more “magic” going on but the AngularJS team argues it’s “good magic”.

Here is the updated AngularJS data binding example showing two parts of the view being updated.

AngularJS creates the person object on the scope for you when you data bind with the ng-model attribute so the example is very terse and includes no JavaScript. Here is what the JavaScript it generates would look like.

This may not be the most fair comparison because we haven’t created multiple controllers to manage the different parts of the view as we did with Backbone but regardless it will end up being significantly less code with AngularJS.

Data Storage

AngularJS Example

AngularJS handles data in two different ways. First, by providing support for manual AJAX calls in a very similar way to jQuery $.ajax functionality via $http. In addition, if your backend is a strictly RESTful service, AngularJS provides a $resource class that makes calls to the RESTful service extremely terse.

$http example
app.factory('myService', function($http) {
   return {
     getFooOldSchool: function(callback) {
       $http.get('foo.json').success(callback);
     }
   }
});
 
app.controller('MainCtrl', function($scope, myService) {
  myService.getFooOldSchool(function(data) {
     $scope.foo = data;
  });
});
$resource example
var Todo = $resource('/api/1/todo/:id');
 
//create a todo
var todo1 = new Todo();
todo1.foo = 'bar';
todo1.something = 123;
todo1.$save();
 
//get and update a todo
var todo2 = Todo.get({id: 123});
todo2.foo += '!';
todo2.$save();
 
//delete a todo
Todo.$delete({id: 123});

Backbone Example

Backbone assumes you are interacting with a RESTful API but allows you to override one method Backbone.sync() if not. You tell your model where the resource is on the server (the URL) and then you can just call save.

var UserModel = Backbone.Model.extend({
        urlRoot: '/user',
        defaults: {
            name: '',
            email: ''
        }
    });
    var user = new Usermodel();
    // Notice that we haven't set an `id`
    var userDetails = {
        name: 'Craig',
        email: 'craigmc@funnyant.com'
    };
    // Because we have not set an `id` the server will call
    // POST /user with a payload of {name:'Craig', email: 'craigmc@funnyant.com'}
    // The server should save the data and return a response containing the new `id`
    user.save(userDetails, {
        success: function (user) {
            alert(user.toJSON());
        }
    })

Ember Example

Ember has Ember Data which is not technically part of the core framework but is shooting to provide a more robust data persistence/data storage story. It provides many of the facilities you’d find in server-side ORMs like ActiveRecord, but is designed specifically for the unique environment of JavaScript in the browser. At the time of writing however the Ember Core Team is close to releasing v1.0 but has not and most Ember projects simply using the $.ajax methods in jQuery just as AngularJS uses $http in the above examples.

We’re all in the same gang

This post broke down JavaScript MV* frameworks into features to provide insight into what functionality is provided by these frameworks and to bring readers to the realization that they are actually very similar. Once you understand the features and how they fit together it becomes much easier to quickly learn multiple frameworks and find the right one for your project. If this post helped you have an “Ah-hah moment” or get up to speed quickly please share it on Twitter and Google+ (below) or if you are further along let people know in the comments how your project with one of these frameworks (or other similar) is going. If you are new to my site consider signing up for my free 7 day E-Course “JavaScript MVC Framework Comparison” below.

16 Responses to “JavaScript Frameworks | How to Learn Them Quickly”

  1. Cristian Rivera March 25, 2014 at 2:05 pm #

    This is great thanks!
    one only request, please expand on the Knockout alternatives to those MV* features a bit more.

    • Craig McKeachie March 26, 2014 at 7:51 am #

      Will do. Thanks Christian. Off my head though Durandal is commonly thought of a great compliment to Knockout.

  2. Royce Lithgo March 25, 2014 at 11:27 pm #

    Nice intro article. I am only concerned with Angular, so i skipped all the other frameworks.
    I’ve been learning Angular for some time now and still struggling to get my project off the ground. My issue is learning best practices for Angular development. Angular docs never really touch on best practices. The blogsphere usually has differing opinions on this subject as well.

    • Craig McKeachie March 26, 2014 at 8:09 am #

      You’re probably aware of this site since you are focused on AngularJS but Egghead.io is a great resource (particularly some of the newer videos for best practices). I’ve heard good things about the AngularJS in Action Manning book which is in early access but I’ve only read a couple articles on the author’s blogs so far. The AngularJS documentation does leave a lot to be desired but can be humorous at times.

  3. Tim March 27, 2014 at 8:21 am #

    Nice article, thank you and good luck with your course.

    It can be overwhelming to learn these various frameworks to decide which is the right one for your specific needs. The underlying concepts (e.g. models) don’t always have parallels between frameworks and you can quickly get lost in terminology. You also have the option of composing your own framework from libraries, which may be a better options for some people.

    TodoMVC (http://todomvc.com/) is a great resource for comparisons, but my advice is to just dive in and build sample applications which have the same basic needs as your real-world projects.

    I did this here with Angular and Durandal (http://timplourde.github.io/mv-crud/) for a financial app and I hope to add more implementations as time permits. If you’re reading this and stressed out trying to choose a framework / library, I recommend you do something similar.

  4. Alex Marandon March 29, 2014 at 7:19 am #

    Thanks for this interesting post. It helped me clarify those concepts after having looked a bit into CanJS and AngularJS.

    Being new to MV* JavaScript frameworks, one thing that surprises me is how they all seem to make strong assumptions about the server API. Actually I’m a bit bothered by the way you use the word RESTful here. In order to use those frameworks with their default settings, the server API not only needs to be RESTful(ish), but it needs to implement a very specific API. Many RESTful APIs, for instance those based on standardized hypermedia formats, will not work with those frameworks out-of-the-box. It seems that people designing those frameworks expect server APIs to satisfy client code rather than designing clients that consume well designed APIs. The kind of API that those frameworks encourage is even questionable. For instance serving arrays at the top level of JSON documents isn’t considered good practice.

    It seems that the world of hypermedia RESTful APIs and client-side MV* frameworks largely ignore each others, which is a shame because it seems that there’s a good potential for them to work together. APIs based on standards including hypermedia controls could help creating more generic and reusable client-side code.

    • Craig McKeachie March 29, 2014 at 12:31 pm #

      Hi Alex,

      Your comments about the APIs required by frameworks being RESTful(ish) were insightful. I’m concerned when you say “they all seem to make make strong assumptions about the server API” could be taken the wrong way by readers. To be clear, all frameworks have a way to just make AJAX calls to the server like jQuery (generally they actually use jQuery to do this) in which case they are all pretty agnostic to whatever you want to do with your server API.

      I personally was surprised about how little the frameworks do to help you when interacting with the server and agree that it does seem a shame because their is a lot of potential for them to work together.

  5. Ibrahim March 29, 2014 at 7:56 am #

    According to your comparison, I’d say Angular does a lot of stuff under the hood and makes use of ‘magic’ whereas, Backbone’s code is more verbose IMO. Can we say one of Backbone’s strength is ‘Code Verbality’ ?

    • Craig McKeachie March 29, 2014 at 11:53 am #

      I guess so but I had to look up ‘Verbality’ to see if it really was a word ;-). It’s just a classic trade-off, verbality is useful when you need to go low level (I think the common case for this is integrating with widgets, controls such as jQueryUI and Bootstrap) while terse code is productive on every day repetitive tasks such as mapping views to models or visa-versa.

  6. Ahmed Assaf April 3, 2014 at 9:47 am #

    Nice Article

  7. Benjamin April 8, 2014 at 4:42 am #

    Nice works. It would be interesting to add Meteor (with iron-router for routing) in the article.

    • Craig McKeachie April 9, 2014 at 1:12 pm #

      Just went to my local JavaScript user’s group and got to know Meteor better a few weeks back so perhaps I’ll get to adding it. My initial reaction to it was I seemed to be “extremely productive” using it.

  8. Phil Renaud April 9, 2014 at 12:32 pm #

    “most Ember projects simply using the $.ajax methods in jQuery just as AngularJS uses $http in the above examples.”

    Hm — is that true? I’ve found that for any app that uses data and cares about sync, Ember Data provides a ton of advantage over getJSON / Angular’s $http. The only caveat tends to be that one’s api should be conventional.

    Great writeup!

    • Craig McKeachie April 9, 2014 at 1:08 pm #

      I think it is true when you consider Discourse (the most public decent sized Ember app currently) does this and Tom Dale himself pretty much concedes it in my podcast interview with him here. Although on the other hand adoption seems to be climbing for Ember and who knows how many apps are being built behind corporate walls using Ember Data despite it still being in Beta although apparently not for long.

  9. Robert June 18, 2014 at 3:31 am #

    Silly question: For a new project when and why should I not use AngularJS? Actually, the same could be asked for any other framework (or combination of libraries). If we would have a list of frameworks and recommendations when not to use a particular one then decisions could be done faster maybe.

    For me, there are too many framework (seen at todomvc.com). I cannot test them all. I would be glad if someone could just advice me to use framework X since it can be used in most situations.

    • Craig McKeachie July 25, 2014 at 8:53 am #

      If you haven’t already please check out my book 270 page book the JavaScript Framework Guide which aims to help people quickly get up to speed and make the best decision for their project.

Leave a Reply