chukoe
chukoe

Reputation: 11

Backbone fetching multiple models

I have been working with backbone a bit and I'm quickly finding out what I'm doing has become too tedious and repetitive.

I will have multiple backbone views and each of those views will have a model that makes a call out to an api for data. Once that is complete I want to render the results. Easy enough, however, I have to attach to each of these models data from another source (a messaging system)

//this corresponds to the view
$.when(this.model.fetch(), this.msg.fetch()).done((result1, result2) => {
    this.model.set('msg', this.msgtoJSON(), { silent: true });
    this.renderTemplate(template, this.model.toJSON());
});

This works, but it's repeated, everywhere. I have dozens and dozens of views with this. This also prevents me from attaching object listeners for change events on the main model so that the template can be rendered anew.

Does anyone have any suggestions as to how I could asynchronously have this messaging dependency fetched and injected into my backbone models when those models are fetched?

Upvotes: 1

Views: 872

Answers (1)

vvahans
vvahans

Reputation: 1857

You can make them dependent, merging the fetch of both models. It's will break a bit native implementation of Backbone.Model.fetch, but will help you to avoid code repetition. Kind of denormalize to normalize.

var Slave = Backbone.Model.extend({
     urlRoot: 'first/api',
     defaults: {
         val1: '',
         val2: ''
     }
});  

var Master = Backbone.Model.extend({
    initialize: function(options) {
        this.slave = options.slave;
    }, 
    urlRoot: 'second/api', 
    fetch: function(options) {
        var that = this,
            masterPromise = this.constructor.__super__.fetch.call(this, options);

        if (this.slave) {
            return $.when(masterPromise, this.slave.fetch()).done(function(result1, result2){ //merged promise
                that.set('msg', that.slave.toJSON(), { silent: true });                 
            });
        }
        return masterPromise;
    }
});

And then:

var slave  = new Slave(),
    master = new Master({ slave: slave });

master.fetch().done(function(){
   // render template here.
})

This implementation will work for both cases, with slave model or without.

A few things to note

1.If you handle success callback to render the template like:

master.fetch({success: function() { // rendering here}});

in this case 'msg' will be undefined, cause success will not wait for slave's promise. You need to avoid use of success.

2.If one of the model's fetch will fail, and you will set the fail callback on merged promise it will fire whenever one of the model's fetch has failed. If you need to do some staff individually for each model's fail case you need to attach them to the model's fetch before merged promise.

PS. I haven't tested this code, so please let me know if something fails.

Upvotes: 2

Related Questions