sntran is right about where your problem is coming from: you're modifying an array while you're iterating over it.
You start off with your new model with nOrder: null
at the beginning of the model list:
splice.apply(this.models, [index, 0].concat(models));
then add
loops through the models triggering 'add'
events as it goes:
for (i = 0, length = this.models.length; i < length; i++) {
if (!cids[(model = this.models[i]).cid]) continue;
options.index = i;
model.trigger('add', model, this, options);
}
But inside your 'add'
callback, you modify the model:
if(model.get('nOrder') == null)
model.set('nOrder', _.max(collection.pluck('nOrder')) + 1);
and then sort the collection:
collection.sort({silent: true});
These two actions move this.models[0]
to this.models[3]
in the event triggering loop; but the i
for that loop will just keep ticking along and the new this.models[3]
(which used to be at 0
) will get past the if (!cids[(model = this.models[i]).cid])
test again and there's your second 'add'
event.
You can watch this version of your fiddle work to see how the collection's array is changing behind your back:
http://jsfiddle.net/ambiguous/p8Fp4/
I think the simplest solution is to add an append
method to your collection that sets the appropriate nOrder
value on the model and then adds it to the collection:
append: function(m) {
var nOrder = _.max(this.pluck('nOrder')) + 1;
if(m instanceof Backbone.Model)
m.set({ nOrder: nOrder });
else
m.nOrder = nOrder;
this.add(m);
}
Then your 'add'
callback can leave nOrder
alone and stop sorting the collection.
Demo: http://jsfiddle.net/ambiguous/JqWVP/
You could also override the collection's add
method but that is a lot more complicated if you want to do it right.