I'm relatively new to Backbone.js. I'm initializing a collection view and passing in a collection at creation time.
suggestionsView = new TreeCategoriesAutoSuggest.Views.Suggestions({
collection: new App.Collections.Suggestions(this.getSuggestions(query))
});
I then render the collection view. Each time a user enters a query into a text box the collection is regenerated and assigned to the collection view using:
suggestionsView.collection.set(this.getSuggestions(query));
This takes care of the adding/removing of models in the collection but how do I manage the adding/removing of views for the added/removed models?
I should mention that I have used the this.collection.on("add") listener in the collection view. But this gets triggered for every model that is added. I also tried this.model.on("change") from within the individual view but this is not fired when models are added/removed from collections.
Any help/guidance appreciated!
Update
I am now using:
suggestionsView.collection.reset(this.getSuggestions(query));
And when the reset event is fired I'm removing the suggestion sub views, re-initializing them for the new collection and re-rendering the collection view.
handleReset: function(){
console.log("reset");
this.cleanupOldViews();
this.initViews();
},
initViews: function(){
this.collection.each(function(suggestion){
this.suggestionViews.push(new TreeCategoriesAutoSuggest.Views.Suggestion({
model: suggestion
}));
},this);
},
cleanupOldViews: function(){
_.each(this.suggestionViews,function(suggestionView){
suggestionView.remove()
},this);
this.suggestionViews = [];
}
So you think I don't need to worry about destroying the models?
Bulk replacements are easier and more efficient using reset
:
reset
collection.reset([models], [options])
Adding and removing models one at a time is all well and good, but sometimes you have so many models to change that you'd rather just update the collection in bulk. Use reset to replace a collection with a new list of models (or attribute hashes), triggering a single
"reset"
event at the end. Returns the newly-set models. For convenience, within a"reset"
event, the list of any previous models is available asoptions.previousModels
.
So instead of using set
to merge the changes and generate a bunch of 'add'
and 'remove'
events, using reset
and listen for 'reset'
event:
// In the view's `initialize`...
this.listenTo(this.collection, 'reset', this.render);
and then render
can redraw the whole thing and you'd say:
suggestionsView.collection.reset(this.getSuggestions(query))
// ------------------------^^
to refresh things.
Some clarification from the comments: Models don't generate 'add'
events, only collections trigger those. Models trigger 'change'
events when their properties change, collections trigger 'add'
and 'remove'
events when models are added and removed (respectively) from them; collections can also trigger 'change'
events because they forward all the events from their enclosed models:
Any event that is triggered on a model in a collection will also be triggered on the collection directly, for convenience.
So if you want to use Collection#set
then you'd want three handlers in your view:
this.listenTo(this.collection, 'add', ...)
: A new model has been added to the collection so render it.this.listenTo(this.collection, 'remove', ...)
: A model has been removed from the collection so remove its part of the view.this.listenTo(this.collection, 'change', ...)
: A model has changed so update its part of the view.If you're only working with small collections then reset
might be less work. If your collections are larger or the view changes are more expensive then dealing with the three events separately might be best.
In any case, if you're using sub-views, you'll want to maintain a list of them somewhere in the parent view so that you can call remove
on them to make sure things are properly cleaned up. If you're destroying the models when removing them from the collection, you could have the sub-views bind to their model's 'destroy'
events and remove themselves as needed.
The Catalog of Events might be worth a review to see what events are triggered at which times.