可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.