Frankie
Frankie

Reputation: 2265

How to wait to render view in backbone.js until fetch is complete?

I'm trying to understand how a portion of backbone.js works. I have to fetch a collection of models once the app begins. I need to wait until fetch is complete to render each view. I'm not 100% sure the best approach to take in this instance.

var AppRouter = Backbone.Router.extend({
    routes: {
        "": "home",
        "customer/:id": "customer" 
    },

    home: function () {
        console.log("Home");
    },

    customer: function (id) {
        if (this.custromers == null)
            this.init();

        var customer = this.customers.at(2); //This is undefined until fetch is complete. Log always says undefined.
        console.log(customer);
    },

    init: function () {
        console.log("init");
        this.customers = new CustomerCollection();
        this.customers.fetch({
            success: function () {
                console.log("success"); 
                // I need to be able to render view on success.
            }
        });
        console.log(this.customers);
    }
});    

Upvotes: 50

Views: 59856

Answers (6)

Saraf Sissddharth
Saraf Sissddharth

Reputation: 175

You Can Use on and Off Methods

if you want to add trigger method like suppose if you want on success you want to call render method so please follow below example.

    _this.companyList.on("reset", _this.render, _this);
    _this.companyList.fetchCompanyList({firstIndex: 1, maxResult: 10},     _this.options);

in Model js please use like

    fetchCompanyList: function(data, options) {
    UIUtils.showWait();
    var collection = this;
    var condition = "firstIndex=" + data.firstIndex + "&maxResult=" + data.maxResult;
    if (notBlank(options)) {
        if (notBlank(options.status)) {
            condition += "&status=" + options.status;
        }
    }
    $.ajax({
        url: "webservices/company/list?" + condition,
        type: 'GET',
        dataType: 'json',
        success: function(objModel, response) {
            UIUtils.hideWait();
            collection.reset(objModel);
            if (notBlank(options) && notBlank(options.triggerEvent)) {
                _this.trigger(options.triggerEvent, _this);
            } 
        }
    });
}

Upvotes: 0

Rovanion
Rovanion

Reputation: 4582

The method I use is the jQuery complete callback like this:

var self = this;
this.model.fetch().done(function(){
  self.render();
});

This was recommended in a Backbone bug report. Although the bug report recommends using complete, that callback method has since been deprecated in favor of done.

Upvotes: 65

IcedDante
IcedDante

Reputation: 6802

Another option is to add the following inside of your collections initialize method:

this.listenTo(this.collection, 'change add remove update', this.render);

This will fire off the render method whenever the fetch is complete and/or the collection is updated programmatically.

Upvotes: 1

Martin
Martin

Reputation: 755

Another useful way might be to bootstrap in the data directly on page load. This if from the
FAQ:

Loading Bootstrapped Models

When your app first loads, it's common to have a set of initial models that you know you're going to need, in order to render the page. Instead of firing an extra AJAX request to fetch them, a nicer pattern is to have their data already bootstrapped into the page. You can then use reset to populate your collections with the initial data. At DocumentCloud, in the ERB template for the workspace, we do something along these lines:

<script>
  var Accounts = new Backbone.Collection;
  Accounts.reset(<%= @accounts.to_json %>);
  var Projects = new Backbone.Collection;
  Projects.reset(<%= @projects.to_json(:collaborators => true) %>);
</script>

Upvotes: 2

iririr
iririr

Reputation: 261

You can also do this with jquery 1.5+

$.when(something1.fetch(), something2.fetch()...all your fetches).then(function() {
   initialize your views here
});

Upvotes: 24

tkone
tkone

Reputation: 22728

You can send your own options.success to the collections fetch method which runs only when the fetch is complete


EDIT (super late!)

From the backbone source (starting line 624 in 0.9.1)

fetch: function(options) {
  options = options ? _.clone(options) : {};
  if (options.parse === undefined) options.parse = true;
  var collection = this;
  var success = options.success;
  options.success = function(resp, status, xhr) {
    collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
    if (success) success(collection, resp);
  };

Note the second to last line. If you've passed in a function in the options object as the success key it will call it after the collection has been parsed into models and added to the collection.

So, if you do:

this.collection.fetch({success: this.do_something});

(assuming the initialize method is binding this.do_something to this...), it will call that method AFTER the whole shebang, allowing you trigger actions to occur immediately following fetch/parse/attach

Upvotes: 10

Related Questions