Posted on Jan 03, 2012 by

Introduction to Backbone.js with jQuery Mobile

If you are working on a JavaScript heavy application (think jQuery Mobile, etc.), you probably will want to look at some JavaScript libraries to help add structure, consistency and convenience to your applications. One of the JavaScript libraries I've used lately is Backbone.js. To quote Backbone themselves, it provides "models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.". This is really a great summary of what Backbone can provide to your application.

As an example of how to apply Backbone, I'll create a small jQuery Mobile app and use a Backbone model, collection and view to render the user interface. Through the use of Backbone's event model, the user interface will update as the model changes or new models are created.

I decided to use jQuery Mobile as the UI framework mainly because I am a mobile guy and it will provide the HTML with some reasonable style with no additional effort on my part. I know, lazy...but it works for this blog post :) Continuing on the lazy path, I will refer to jQuery Mobile as JQM from this point forward.

The following assumes you are at least a little familiar with jQuery and JQM. If not, take a look at the JQM website (http://jquerymobile.com/). They have some great documentation and even a template for creating a basic app. All of the code in this post will be available in my github repository (https://github.com/stevenpsmith/Exercise/tree/BackboneIntro).

The application we are going to make will allow a user to log exercise they have done on any given day. Please remember this is a very basic app for the sole purpose of demonstrating Backbone.js. The piece that will be developed for this post will involve pulling exercise data from a server and presenting it in a list view, a very common paradigm for mobile apps. In the end, our app will look like this:

ListView

The JSON we will be dealing with will look like this:

I like to organize my application structure a little differently than the JQM introduction shows, mainly for organizational reasons. My application structure looks like this:

dir_structure

All of our work will be done in index.html and app.js. In real applications I usually break down my JS files even further, but it really isn't necessary here. The list page of the application is defined within index.html. It should look like a typical JQM page definition with the only the content portion defined. We will use the Backbone View to create the list view:

If we view this in the browser, we get an empty page with an add button in the header. Since we want to populate our list view with data, we should define a Backbone model and collection in order to manipulate and store the data via JavaScript. A basic model and its collection are easily defined:

The great thing about the collection is it provides a RESTful access back to your server for data retrieval and persistence. To keep this simple, our data will be served from a static JSON file with the structure referenced earlier. Since we have no real server side in this example, we can't really save our changes anywhere but in the client's memory. But the collection will fetch the data from the server and can be used to help render our user interface. The following code will create an instance of the collection in memory, retrieve the data from the server, and parse it into a collection of models.

The exercise.initData() function can be called during initialization of the application (or wherever else might be appropriate) to load the data. Now it is time to render the view. Backbone views depend upon Underscore.js. Underscore is a utility library that includes a lot of great features, one of which is view templates. Backbone can be used with many view template frameworks (e.g. Mustache, Handlbars, etc.), but here we will stick with Underscore templates as they meet our needs. For our exercise activity items, we need a very basic template like this:

Giving the template a unique id will let us access it using typical jQuery selectors. The data driven parts of the template are surrounded by

As you can see in line 2, we are using the id, date, and type attributes of whatever model is supplied to the template to fill in the HTML accordingly. While the "identifier" attribute is not a real HTML attribute and not required by any of the frameworks, it would be used to determine what activity the user selected in the list so the appropriate data could be retrieved and displayed on a subsequent page.

The next step is to define the Backbone View that will render the list view. Backbone views can be defined and set up numerous ways, and the documentation does a great job explaining the options, etc. I like to define my views so that they are as self contained as possible. So, rather than allowing Backbone to create the HTML within a DIV (the default behavior), I define the appropriate properties to create a JQM list view as shown in lines 2-4 below:

From the Backbone site: "The default implementation of render is a no-op. Override this function with your code that renders the view template from model data, and updates this.el with the new HTML. A good convention is to return this at the end of render to enable chained calls". The $(this.el) refers to the containing element, in this case the ul element. There are standard attributes that are accessible from within the Backbone View including collection and model. Lines 17-20 iterate over the collection of activities, fills in the template placeholders with the data from the model, and appends the resulting HTML to the containing element.

If you need to pass arbitrary data to your view, it can be accessed via the options object as shown on line 11 of the code snippet. As mentioned earlier, I like my Backbone Views to be as self contained as possible, so I provide the containing HTML element for this view (as a jQuery object) when constructing the View instance. Line 20 sets the HTML of the containing element to the Backbone View and line 21 tells JQM to style things appropriately.

The next step is to instantiate and render the view with the appropriate collection and HTML container. Since this is the "home" page in our application, this is done after JQM initializes the page.

Now we have a list view that renders a JQM list based on data in a Backbone collection. To take advantage of the real power of Backbone models/collections, we can add listeners for changes to the collection that will update the view based on those changes. The beauty of this is the additional code to accomplish this is minimal. By adding

this.collection.bind('add', this.add, this);

to the initialize method of our Backbone View and providing an add() method. Here we are just grabbing the list view and appending the new model to the view (and refreshing it so JQM does its magic). By adding a click handler to the "Add" button, we can test that adding a model to the collection updates the view.

There are other methods on which to bind, but this provides a quick example on how Backbone can be used to assist with view rendering and data handling in JavaScript based client applications. The entire code base is available here. It can be deployed on any web server. For OS X, I use the built in web server, but feel free to use the server of your choice.

Related Posts:

Tags: , , , , ,

  • http://www.blogger.com/profile/03205567992253832452 tbranyen
    Setting async to false is a horrible practice and should never be advocated.

    exercise.activities.fetch({async: false}); // use async false to have the app wait for data before rendering the list

    Can you justify the decision to block the event loop?
  • http://candanny.wordpress.com/ candanny
    Thanks for spending the time to write this up. I keep looking at backbone tutorials to be convinced that backbone.js will help me and not confuse matters, but in the end I am still not convinced that it's more intuitive than using templates and jQuery directly. Or maybe backbone proves more worthwhile in bigger apps? Have you seen the plain jQuery todo MVC version on github (addyosmani / todomvc)?
  • http://www.blogger.com/profile/09338685521155647464 glfp
    A really interesting article. I'm working on JQM since very few weeks, and I'm very fed up of it's page transitions mechanism .... and using javascript client-side it's very terrible.

    Did you test JS + backbone with many page transitions and values passed from one page to another ?

    Thank you.

    Gian Luca - Italy
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    tbranyen:

    In this example application, the first (and only) view is data driven from backbone collection. In order to render this view, the collection needs to be populated. Therefore, I need the rendering to wait for the collection to be loaded via the ajax call. Without that, the view renders an empty list. I did this for simplicity sake, as the point here is to provide an example of how to use backbone with JQM, not to provide best practices or standards for JQM. While most of the time ajax calls should be asynchronous, there are times when they need to be synchronous as well. One project I worked on required multiple REST calls to synchronize browser local storage with a server side application. The way the existing REST interface was defined, there could be cases were certain calls should not be made based on the outcome of previous calls (i.e. there were some dependencies between calls). This necessitated the use of the async:false option. So to say that something should "never be advocated" is a bit extreme when it comes to software development.
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    candanny:

    I have not seen the TodoMVC app (http://addyosmani.github.com/todomvc/) before. Based on a quick look, it looks very interesting and I plan on digging in deeper. Thanks for pointing that out. I have used Sencha Touch and am hoping to create a mirror app to provide a comparison between Backbone/JQM and Sencha, but workload will dictate how soon that can happen.
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    glfp:

    We have done some testing with various amounts of data, and performance isn't always the greatest. BTW, you can turn off transitions in JQM with this line of code: $.mobile.defaultPageTransition = 'none'. The last project I worked on we decided that rather than pass data between pages, we used session storage to put/get data based on our current operating context. Of course, we had a requirement for offline storage, so we knew the browsers would support session storage as well.
  • http://www.blogger.com/profile/07242435965833662812 ajs
    Great to see some more information on this combination. I started a project using jQM and backbone about 5 months ago and have been rather happy with the choice of doing MVC in the browser using these tools. There are a couple of interesting subtleties that I've run into and I want to point out to provoke some discussion.

    1. Both jQM and backbone provide hashchange listening navigation support. I ended up choosing to disable it in jQM and use just backbone. I'd be interested to see what other people have chosen and how its working out for them.

    2. I found that when the underlying model gets sufficiently complicated, I had to adopt a policy of wrapping a view side event handler in a _.defer whenever binding a view object to a model object. This allows all of the bindings between model objects to complete first so that the model is in a consistent state before any of the views try to render. This one is more just about backbone, but again I'm curious to find out what people are doing.

    Thanks for the article.
  • http://www.blogger.com/profile/11221086094145561739 kborchers
    I know I am late to this party but I have to agree with tbranyen here. You should never block with async: false! There is always a way to rewrite your code to use callbacks. Even if some calls to your RESTful API depend on the outcome of other calls, you could make those calls in the success, error or complete callbacks just as easily as with blocking but without the bad user experience of the browser appearing to lock up.

    Also, when you said "I did this for simplicity sake, as the point here is to provide an example of how to use backbone with JQM, not to provide best practices or standards for JQM", that is not a valid argument. When posting examples for others to follow, you should always post those examples using best practices. Posting poorly executed code just promotes bad practices in this world where unfortunately copy/paste is more prevalent than understand/implement, even if promoting those bad practices is unintentional.
  • http://www.blogger.com/profile/10528002201560565334 JB
    I really agree with your blog.I keep looking at backbone tutorials to be convinced that backbone.js will help me and not confuse matters, but in the end I am still not convinced that it's more intuitive than using templates and jQuery directly.Thanks for the sharing!!
    Create Mobile App