Sunday, Jun 24, 2012

How to indicate Backbone fetch progress

While developing GitHub Viewer,, I received a lot of feedback on how to make the application more user friendly. One suggestion was to add loading spinners while the application fetched data from the GitHub API.

This may seem relatively trivial, but I wanted to do this in a very evented way to correspond with how the Views are already rendered. My solution ended up patching the fetch method on Collection.prototype to emit a fetch event.

The code could easily be expanded to work with Models as well and would look something like this:

// Patch Model and Collection. _.each(["Model", "Collection"], function(name) { // Cache Backbone constructor. var ctor = Backbone[name]; // Cache original fetch. var fetch = ctor.prototype.fetch; // Override the fetch method to emit a fetch event. ctor.prototype.fetch = function() { // Trigger the fetch event on the instance. this.trigger("fetch", this); // Pass through to original fetch. return fetch.apply(this, arguments); }; });

The code above will iterate over both the Model and Collection names and patch the fetch method on both to trigger an event that signifies fetching has started. This is fantastic for our auto-updating Views.

A sample View that auto-updates might look something like this:

Repos.Views.List = Backbone.View.extend({ initialize: function() { // Display a loading indication whenever the Collection is fetching. this.collection.on("fetch", function() { this.html("<img src='/assets/img/spinner.gif'>"); }, this); // Automatically re-render whenever the Collection is populated. this.collection.on("reset", this.render, this); } });

This makes it much easier to drive your Views with a loading indicator and then have them rendered once the Collection/Model has been populated or changed.

The fetch event works great for when data is currently being loaded, if you want to know when data has successfully been sync'd from the server, simply use the sync event on the Collection/Model.

I would love to see this event made into Backbone core, so that I no longer have to patch it directly.