Wait for the collection to fetch everything in bac

2019-04-04 01:01发布

问题:

I have two set of collections. One is for the categories and the other is for the Items. I ned to wait for the categories to finish fetching everything for me to set the category for the Items to be fetched.

Also i everytime i click a category i must re-fetch a new Items Collection because i have a pagination going on everytime i click on a category it doesn't refresh or re-fetch the collection so the pagination code is messing with the wrong collection. Any ideas?

this.categoryCollection = new CategoryCollection();
this.categoryCollection.fetch();

this.itemCollection = new ItemCollection();
this.itemCollection.fetch();

回答1:

One quick way would be to just pass a callback into the first fetch() call that invokes the second. fetch() takes an options object that supports a success (and error) callback.

var self = this;
this.categoryCollection = new CategoryCollection();
this.categoryCollection.fetch({
    success: function () {
        self.itemCollection = new ItemCollection();
        self.itemCollection.fetch();
    }
});

Not the most elegant, but it works. You could probably do some creative stuff with deferreds since fetch() returns the jQuery deferred that gets created by the $.ajax call that happens.

For the pagination issue, it's difficult to tell without seeing what your pagination code is doing. You're going to have to roll the pagination stuff yourself since Backbone doesn't support it natively. What I'd probably do is create a new Collection for the page criteria that are being queried and probably create a server action I could hit that would support the pagination (mapping the Collection's url to the paginated server action). I haven't put a ton of thought into that, though.



回答2:

Just ran into a similar situation. I ended up passing jquery.ajax parameters to the fetch() call. You can make the first fetch synchronous. From the backbone docs:

jQuery.ajax options can also be passed directly as fetch options

Your code could be simplified to something like:

this.categoryCollection.fetch({async:false});
this.itemCollection.fetch();


回答3:

I had to react to this thread because of the answers there.

This is ONLY WAY OF DOING THIS RIGHT!!!

this.categoryCollection = new CategoryCollection();
this.itemCollection = new ItemCollection();

var d1 = this.categoryCollection.fetch();
var d2 = this.itemCollection.fetch();

jQuery.when(d1, d2).done(function () {
     // moment when both collections are populated
     alert('YOUR COLLECTIONS ARE LOADED :)'); 
});

By doing that you are fetching both collections at same time and you can have event when both are ready. So you don't wait to finish loading first collections in order to fetch other, you are not making ajax calls sync etc that you can see in other answers!

Here is a doc on Deferred objects.

Note: in this example case when one or more deferred object fails it's not covered. If you want to cover that case also beside .done you will have to add .fail callback on .when and also add error handler that will mark failed d1 or d2 in this example.



回答4:

I am using RelationalModel and I created a queued fetch, that only calls the 'change' event when done loading:

var MySuperClass = Backbone.RelationalModel.extend({
    //...

    _fetchQueue : [],

    fetchQueueingChange : function(name){
        //Add property to the queue
        this._fetchQueue.push(name);
        var me = this;

        //On fetch finished, remove it
        var oncomplete = function(model, response){
            //From _fetchQueue remove 'name'
            var i = me._fetchQueue.indexOf(name);
            me._fetchQueue.splice(i, 1);

            //If done, trigger change
            if (me._fetchQueue.length == 0){
                me.trigger('change');
            }
        };

        this.get(name).fetch({
            success: oncomplete, 
            error : oncomplete
        });
    },

    //...


});

The class would call:

this.fetchQueueingChange('categories');
this.fetchQueueingChange('items');

I hope you can improve on this, it worked well for me.



回答5:

I ended up with the same problem today and figured out a solution to this:

var self = this;
this.collection = new WineCollection();
this.collection.url = ApiConfig.winetards.getWineList;
this.collection.on("reset", function(){self.render()});
this.collection.fetch({reset: true});

Now when the fetch on the collection is complete a "reset" is triggered and upon "reset" call the render() method for the view.

Using {async: false} is not the ideal way to deal with Backbone's fetch().



回答6:

just set jQuery to become synchronous

$.ajaxSetup({
  async: false
});   
this.categoryCollection.fetch();
this.itemCollection.fetch();
$.ajaxSetup({
  async: true
});

This is the simplest solution, I guess. Of course, starting new requests while these fetches run will be started as synchronous too, which might be something you don't like.



标签: backbone.js