0

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

由于我的 add 事件做了一些 DOM 插入,我最终在我的 DOM 中得到了重复的项目。

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

查看完整的小提琴:http: //jsfiddle.net/DD23n/9/

4

2 回答 2

4

sntran关于您的问题的出处是正确的:您在迭代数组时正在修改它。

您从nOrder: null 模型列表的开头开始使用新模型:

splice.apply(this.models, [index, 0].concat(models));

然后add 循环遍历触发'add'事件的模型:

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]事件触发循环中移动;但是ifor 那个循环会一直滴答作响,新的this.models[3](曾经是 at 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方法,但如果您想正确地执行此操作,则要复杂得多。

于 2012-06-07T23:30:24.237 回答
2

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

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

但是你调用sort一个add处理程序,collection.models变得不同。当集合执行其循环add功能时,插入模型将位于不同的位置,它将再次触发“添加”。

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

于 2012-06-07T19:25:53.357 回答