8
votes

Context: I am building an application that needs several large collections of reference data to operation. I am limited to HTML and Javascript only (including JSON).

Question: How do I bootstrap a collection in Backbone.js where the collection objects are in JSON format on the server and I'm using Javascript only?

This is what I know already:

  • Backbone.js bootstrapping best practice requires Rails or some other server-side language (http://backbonejs.org/#FAQ-bootstrap).
  • Most Javascript I/0 operations are asynchronous, such as loading JSON from the server.
  • Using fetch() to bootstrap data is considered an anti-pattern in Backbone.js. fetch() is also also an asynchronous operation.

This is what I've come up with so far:

ItemList = Backbone.Collection.extend({
  model: Item,
  url: 'http://localhost:8080/json/items.json'
});
var itemList = new ItemList;
itemList.fetch();
itemList.on('reset', function () { dqApp.trigger('itemList:reset'); });

'dqApp' is my application object. I can display a spinner, and update a loading status while collections are being populated by sending alerts to the application object.

3

3 Answers

1
votes

The fetch function accepts an options parameter, which can have a success callback:

var itemList = new ItemList;
itemList.fetch({success: function () {
    dqApp.trigger('itemList:reset');
}});
0
votes

One possible solution is to make your view dependent on the status of fetch, so it doesn't get instantiated until your model/collection has finished loading.

Just keep in mind this is a Backbone anti-pattern. Making the view dependent on your collection/model will likely cause UI delays. That's why the recommended method is to bootstrap your data by inlining the json directly in your page.

But this doesn't solve your situation, where you need to bootstrap data on a server-less situation. It's easy to embed json data in your page dynamically with a few lines of Ruby/PHP/etc, but if you're working client-side only, making the view dependent on the model is the way to go.

If you're loading the collection using fetch(), you can use something like:

var Model = Backbone.Model.extend({});

var Collection = Backbone.Collection.extend({
    model: MyModel,
    url: 'http://localhost:8080/json/items.json'
});

var View = Backbone.View.extend({
    //code
});

var myCollection = new Collection();

myCollection.fetch({
    success: function () { 
        console.log('Model finished loading'); }
        myView = new View();
  });

My preferred way is using ajax (e.g., .getJSON, .ajax) and saving the returned jqXHR object (or XMLHTTPRequest, if you're not using jQuery) to a property in your model. This way you have more granular control, and can use the deferred object response to check for the status of the call before creating your view.

var Model = Backbone.Model.extend({});

var Collection = Backbone.Collection.extend({
    model: Model,
    status: {},
    initialize: function () {
        var _thisCollection = this;
        this.status = $.getJSON("mydata.json", function (data) {
            $.each(data, function(key) {
                var m = new Model ( {
                        "name": data[key].name,
                        "value": data[key].value,
                    } );
                _thisCollection.add(m);
            });
        });
    }
});

var View = Backbone.View.extend({
    console.log( "Creating view...");
    //code
});

var myCollection = new Collection();
var myView = {};
myCollection.status
    .done(function(){
        console.log("Collection successfully loaded. Creating the view");
        myView = new View();
    })
    .fail(function(){
        console.log("Error bootstrapping model");
    });