4

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?

Sudo
  • 559
  • 1
  • 8
  • 15
  • I am facing kinda same problem what i did right now is on success of one fetch i updated the url and fetched again but turns out it updates my whole collection – kishanio Dec 06 '12 at 21:16

2 Answers2

6

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.

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • But there is some method where we can add models directly to collection is there anyway we can keep appending it to the same after every other conventional fetch ? – kishanio Dec 06 '12 at 21:54
  • 1
    @KishanThobhani yes, absolutely. You can use `collection.add(data)` where data is the array. It just depends how you want the events to trigger -- my way above will trigger a single `reset` event, and your suggestion will trigger 4 `add` events. – McGarnagle Dec 06 '12 at 21:56
  • Thanks but i had abit different problem i tried doing this but everything gets buggy. can you have a look at this http://stackoverflow.com/questions/13753540/appending-data-to-same-collection-after-every-pagination-fetch – kishanio Dec 06 '12 at 22:12
  • @KishanThobhani that's why you have to override `fetch` function. The default `fetch` method will always clear and re-create the collection. – McGarnagle Dec 06 '12 at 22:26
  • Urmm okay let me try. Thanks – kishanio Dec 06 '12 at 22:47
  • @KishanThobhani ah, sorry, I was wrong... see Andrew Hubbs' answer on your other question. I guess you can tell Backbone to add rather than reset the whole collection. – McGarnagle Dec 06 '12 at 22:51
1

I know it's an old question, but if someone reaches in here this information may help. To preserve the data previosly fetched by a collection, you can change the url and call the method fetch() any times needed with this options:

reset: false,
remove: false,

Like this

yourCollection.fetch({reset: false, remove: false, [other]: [wathever]})

And that's all, no need for overriding the method. (Maybe in 2012 it was necesary, dunno. The fact is that those options work for Backbone 1.1.2 or later). Be aware that im not sure if this will merge or just add the new data even if it's reppeated.

The documentation (http://backbonejs.org/#Collection-fetch) is a little confusing about the 'reset' option, because it says is settled false by default, perhaps that may only apply when the url remains static and single.