Dom Christie

Using Backbone.js Class Properties as Data Stores: Part 2

A Backbone plugin version of the following can now be found on the backbone-store-collection GitHub repo.

Previously I demonstrated a pattern to add basic data stores to Backbone models. In this post I'll improve this pattern, extending the store's get method to fetch a model from the server if it's not stored locally.

We'll want the API to look something like this:

var post = new Blog.Models.Post({ id: 1 });

Blog.Models.Post.store().get(1, {
  success: function(model, response) {
    // model returned from local collection
    model == post; // true
  }
});

Blog.Models.Post.store().get(2, {
  success: function(model, response) {
    // model fetched from the server
  },
  error: function(model, response) {
    // error
  }
});

As you can see, the new get adds a second parameter, allowing for success/error callbacks.

First we'll try and retrieve the model from the local store, this requires calling the original get (super). If it's found, we just invoke the success callback. Otherwise we create a new model with the id that was passed in, fetch that model from the server, then invoke the appropriate callback. (On error, the blank model is removed from the store.)

Blog.Collections.Posts = Backbone.Collection.extend({

  get: function(id, options) {
    var modelFromStore =
      Backbone.Collection.prototype.get.call(this, id);

    if(modelFromStore) {
      options.success(modelFromStore);
    }
    else {
      var newModel = new this.model({ id: id }),
          _this = this;
      newModel.fetch({
        success: options.success,
        error: function(model, response) {
          _this.remove(model);
          options.error(model, response);
        }
      });
    }
  },

  url: '/posts'
});

I've created Backbone plugin for this, available from the backbone-store-collection GitHub repo. So rather than copying the code above, you can simply do something like:

Blog.Collections.Posts = Backbone.StoreCollection.extend({
  url: '/posts'
});

Models still need to be manually added to the store: see the project readme.