在Add事件处理程序中对Backbone Collection进行排序会重新触发Add事件

时间:2012-06-07 18:41:58

标签: backbone.js backbone-events

我有一个基于模型属性自行排序的集合,有时我想添加一个模型,只计算add事件处理程序中的顺序。问题是当我在add事件处理程序中调用collection.sort()时,由于某种原因它会再次触发add事件。

由于我的add事件会执行一些DOM插入,因此我最终在DOM中获取了重复的项目。

到目前为止,我找到的唯一解决方案是在添加模型或调用_.defer并对集合进行排序然后运行任何其他代码之前计算下一个顺序

请参阅完整的小提琴:http://jsfiddle.net/DD23n/9/

2 个答案:

答案 0 :(得分:4)

sntran关于问题的来源是正确的:你在迭代时修改数组。

您可以使用nOrder: null at the beginning of the model list

开始使用新模型
splice.apply(this.models, [index, 0].concat(models));

然后add loops through the models triggering 'add' events

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);
}

但在你的'add'回调中,你修改了模型:

if(model.get('nOrder') == null)
    model.set('nOrder', _.max(collection.pluck('nOrder')) + 1);

然后对集合进行排序:

collection.sort({silent: true});

这两个操作在事件触发循环中将this.models[0]移动到this.models[3];但是,该循环的i将继续保持一致,而新的this.models[3](曾经是0)将再次超过if (!cids[(model = this.models[i]).cid])测试,并且您的第二个'add'事件。

你可以观看这个版本的小提琴作品,看看集合的阵列是如何在你背后改变的:

  

http://jsfiddle.net/ambiguous/p8Fp4/

我认为最简单的解决方案是在集合中添加append方法,在模型上设置适当的nOrder值,然后将其添加到集合中:

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);
}

然后,您的'add'回调可以单独留下nOrder并停止对该集合进行排序。

演示:http://jsfiddle.net/ambiguous/JqWVP/

您也可以覆盖集合的add方法,但如果您想要做得更好,那就更复杂了。

答案 1 :(得分:2)

如果您阅读了骨干的源代码,add函数会将插入模型连接到collection.models。在这种情况下,你有四个。

因为您没有告诉add函数是静默的,所以它会循环遍历collection.models并触发插入元素的'add'事件。

但是,您在sort处理程序中调用addcollection.models会变得不同。当集合在add函数中循环时,插入模型将处于不同的位置,它将再次触发“添加”。

我不确定它是否有意义,但我认为在循环期间不重新排列/修改数组会更好。