Posted on Jan 09, 2012 by

Sorting collections with Backbone.js and jQuery Mobile

In a previous post, I provided a simple example of rendering an HTML list view using Backbone.js and jQuery Mobile. The code from that example ended up rendering a list like this:

Screen Shot 2011-12-22 at 12.22.21 PM

Notice that the list is presented in the order that came from the JSON.

Also, when items are added to the list, they show up at the bottom. While easy, this isn't the best. In this post, I'll add sorting to the backbone collection and make a small change to the view so that as new items are added, the list is automatically sorted.

Backbone.js makes these changes very easy. In order for a Backbone collection to be sorted, you implement a comparator method on the collection. As models are added to the collection, Backbone will make sure the sorting is maintained based on the comparator implementation. From the Backbone documentation "Comparator functions take a model and return a numeric or string value by which the model should be ordered relative to others".

We will sort our list based on the date the exercise activity occurred. Since comparators must return a number or string for sorting, we will return the time in milliseconds since 1/1/70. Our new collection definition looks like this: If we refresh our browser with the updated collection implementation, notice that the list is now sorted by date.

Screen Shot 2011-12-22 at 12.32.28 PM

If we wanted it sorted descending, we would simply return the negative value of the getTime() method.

If you tried to add a new activity, you'll notice that it shows up at the end of the list. This is due to the fact that we bind a listener to the add method of the collection (line 7 below), and all this does is append the HTML to the end of the list view (line 30 below).

If you were to open a JS console in the browser and investigate the collection by entering

JSON.stringify(exercise.activities)
you would see that the collection is ordered. To fix the HTML representation of the collection all we need to do is replace the add event binding to call render. This will re-render the HTML based on the collection. We can also remove the add method in the View, as it is no longer needed. Our updated View configuration looks like this:

After refreshing the view, the list will continue to be sorted even when adding new activities. Since the code just adds an item with todays date, try typing the following in the JS console

exercise.activities.add({id:12, date:"12/01/2011", type:"Interval Run"});

This should add an item at the top of the list. Now your exercise activity will always be sorted.

The source code can be found in my git repository here. This URL will take you to the "sort" branch. The master branch represents the code from the introduction blog post found here

Related Posts:

Tags:

  • http://www.blogger.com/profile/17998610126498018370 Koljaho
    I can't seem to get the codes working. The only thing I can see when I run the code is only the header with the add button. Any idea why that happens?
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    This comment has been removed by the author.
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    My guess would be that you are not serving the exercise.json file from a server. If you are using OS X, you can use the built-in web server to host the JSON file.
  • http://www.blogger.com/profile/17998610126498018370 Koljaho
    Hi Steve,

    Thank you so much for posting up this tutorial. Definitely help a lot for rookie like me.
  • http://www.blogger.com/profile/12954983840390427217 Gerben
    Is there a reason for not using a Router? I'm trying to implement your example with a router but having difficulties getting it running again.
    Especially implementing the detail view would require a routerview, or is the approach different with JQueryMobile?
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    I haven't used the Router. jQuery Mobile provides these types of capabilities through the $.mobile.changePage(...) utility and the appropriate HTML markup (data-role='page' attribute). I am hoping to write a blog post demonstrating how to implement a details screen (and input form) using Backbone and JQM (building off of this code).
  • http://www.blogger.com/profile/06964434705635638913 Christian Engel
    Sorry, but this tutorial is broken.

    Its not acceptable that ALL elements should be re-rendered, just because ONE element has been added.

    You should find the correct position in the DOM for the new view and insert it there, instead of just dumping all DOM nodes and re-creating them.

    Taking a mobile application for this example makes it even worse, since the battery and processor power of mobile phones is much more limited.
  • http://www.blogger.com/profile/08979713820164614687 Steve Smith
    That is certainly another approach. I am not sure if it is more efficient to iterate over the DOM to determine the correct position and then insert it. It would be great if you could fork the repo and implement your suggestion.
  • http://www.blogger.com/profile/00628686001177255642 Zirong Zhang
    While easy, this isn't the Diablo 3 cd keybest. In this post, I'll add sorting to the backbone collection and make a small change to the view so that
    GW2 Gems as new items are added, the list is automatically sorted.
  • http://www.blogger.com/profile/17249044700533712819 Nothing Worthless
    I agree with Christian. But obviously, it depends on situation. I'm working with a scenario where re-rendering whole collection is not application as:

    1. some parts are interactive. so if user has doing something like editing inline values or so, those get lost
    2. each element in collection is actually an image. so if view is re-rendered, the image loading flickering (the top to bottom loading of image) is just annoying.