How do I replace a model in a Backbone.Collection?
Suppose I have a Backbone.Collection
with three models. I want to replace the middle one, keeping the first and third models in their current positions. (Assume ther开发者_运维知识库e's no comparator
.) How do I do this?
This is a good question and still relevant today, so it's worth answering.
It is possible the functionality used in my answer did not exist when you asked the question, but it is now quite straightforward to do this.
Anyway, lets assume your collection is named myCollection
and already has 3 models stored in it. Lets also say you have a new model named newModel
that you want use to replace the existing middle model in the collection. To replace the middle model, leaving the first and third models untouched, you can do this:
myCollection.remove(myCollection.at(1));
myCollection.add(newModel, {at: 1});
This will do exactly what you want and raise the remove
event for the model removed and the add
event for the replacement, which is what you wanted also.
There is a simple mechanism built into Backbone that handles this issue
myCollection.add(newModel, {merge: true});
You could introduce a replaceAt function in the backbone collection that would look something like this:
replaceAt : function(model, options, replaceIndex) {
this._replaceAt(model, options, replaceIndex);
return this;
},
_replaceAt : function(model, options, replaceIndex) {
options || (options = {});
if (!(model instanceof Backbone.Model)) {
model = new this.model(model, {collection: this});
}
var already = this.getByCid(model);
if (already) throw new Error(["Can't add the same model to a set twice", already.id]);
this._byId[model.id] = model;
this._byCid[model.cid] = model;
model.collection = this;
replacedModel = this.at(replaceIndex)
this.models.splice(replaceIndex, 1, model);
this._cleanModel(replacedModel, options);
model.bind('all', this._boundOnModelEvent);
if (!options.silent) model.trigger('add', model, this, options);
return model;
},
_cleanModel : function (model, options) {
if(!model) return null;
delete this._byId[model.id];
delete this._byCid[model.cid];
delete model.collection;
if(!options.silent) model.trigger('remove', model, this, options);
model.unbind('all', this._boundOnModelEvent);
return model;
},
Its based on the _add and _remove methods. It should fire the appropriate events that you are looking for but I didn't test for that. I tested that it would replace an element in the collection at the appropriate place.
(using backbone .3.3)
One approach is to modify the collection.models
array directly, then call
collection.refresh(collection.models)
However, this will invoke an add
event listing every model. Ideally, I'd want to invoke a remove
event for the model that's removed and an add
event for the new one. I'm not sure whether that's possible without using a comparator
and adding indices on my models...
Although of this question asked a lot of time ago, it relevant even for today.
And actually its very easy.
- we need to get the old model index inside the collection.
- and then add the new one into the collection at the same index position and merge
look in the example below:
var index = collection.indexOf(oldModel); //1
collection.add(newModel, {at: index, merge: true}); //2
Hope it would help somone ...
good luck !
精彩评论