javascriptjquerybackbone.jsbackbone-modelbackbone.js-collections

Fetch data from different urls using the same collection in backbone js


I have a collection which has to call 4 external apis Eg: http://www.abc.com, http://www.fgt.com, http://www.jkl.com and http://www.rty.com.

I have a Collection named Todos.js. Is there a way I can fetch the 4 apis together in a single collection since all the four apis would provide me the same model response So the response I get from the 4 apis has the same data structure i.e. "name" and "link".

Is there a way I can append all the responses in the same collection? What is the best way to achieve this?


Solution

  • I think the way is to override fetch, where you make the Ajax call to each of the APIs. Store the returned partial sets in a temporary array, and when all 4 are complete, create the collection using this.reset. (You could use JQuery's Deferred I suppose, or just keep an internal count of how many calls have returned.)

    Something like this:

    var Collection = Backbone.Collection.extend({
    
        fetch: function() {
            this.completeCount = 0;
            this.errorCount = 0;
            this.temp = [];
            this.urls = [ 'url1', 'url2', 'url3', 'url4' ];
            var self = this;
    
            // make a $.get call for each URL and add
            _.each(this.urls, function(url) {
                $.get(url, { success: function(data) {
                    console.log("Got partial collection from " + url);
                    self.addPartial(data);
    
                    // alternatively, just call "self.add(data);" here
    
                }, error: function(response) {
                    console.log("Oops, the Ajax call failed for some reason... ignoring");
                    self.completeCount ++;
                    self.errorCount ++;
                } });
            });
        },
    
        // add a JSON array that contains a subset of the collection
        addPartial: function(data) {
            this.completeCount ++;
            var self = this;    
    
            // add each item to temp
            _.each(data, function(item) {
                self.temp.push(item);   
            });
    
            // if all have been received, then create the collection
            if (this.completeCount == this.urls.length) {
                this.reset(this.temp);
            }
        }
    });
    

    Here's a Fiddle where I replaced $.get with a method that just returns dummy data after a short delay.

    Response to comment

    Adding the responses to the collection as they come in is probably better (it's easier anyway). Here's an updated Fiddle.