17

在第一次尝试时,我写了

this.collection.each(function(element){
    element.destroy();
});

这不起作用,因为它类似于ConcurrentModificationException在 Java 中删除所有其他元素。

我尝试在模型上绑定“删除”事件以按照建议一步销毁集合中的主干模型来销毁自己?,但是如果我对属于集合的模型调用destroy,这将触发2个删除请求。

我查看了下划线文档,看不到一个each()向后循环的变体,这将解决删除每个元素的问题。

作为销毁模型集合的最干净的方法,您会建议什么?

谢谢

4

7 回答 7

34

你也可以使用一个好的,老式的流行音乐就地销毁:

var model;

while (model = this.collection.first()) {
  model.destroy();
}
于 2012-06-02T00:48:47.750 回答
25

I recently ran into this problem as well. It looks like you resolved it, but I think a more detailed explanation might also be useful for others that are wondering exactly why this is occurring.

So what's really happening?

Suppose we have a collection (library) of models (books).

For example:

console.log(library.models); // [object, object, object, object]

Now, lets go through and delete all the books using your initial approach:

library.each(function(model) {
  model.destroy();
});

each is an underscore method that's mixed into the Backbone collection. It uses the collections reference to its models (library.models) as a default argument for these various underscore collection methods. Okay, sure. That sounds reasonable.

Now, when model calls destroy, it triggers a "destroy" event on the collection as well, which will then remove its reference to the model. Inside remove, you'll notice this:

this.models.splice(index, 1);

If you're not familiar with splice, see the doc. If you are, you can might see why this is problematic.

Just to demonstrate:

var list = [1,2];
list.splice(0,1); // list is now [2]

This will then cause the each loop to skip elements because the its reference to the model objects via models is being modified dynamically!

Now, if you're using JavaScript < 1.6 then you may run into this error:

Uncaught TypeError: Cannot call method 'destroy' of undefined

This is because in the underscore implementation of each, it falls back on its own implementation if the native forEach is missing. It complains if you delete an element mid-iteration because it still tries to access non-existent elements.

If the native forEach did exist, then it would be used instead and you would not get an error at all!

Why? According to the doc:

If existing elements of the array are changed, or deleted, their value as passed to callback will be the value at the time forEach visits them; elements that are deleted are not visited.

So what's the solution?

Don't use collection.each if you're deleting models from the collection. Use a method that will allow you to work on a new array containing the references to the models. One way is to use the underscore clone method.

_.each(_.clone(collection.models), function(model) {
  model.destroy();
});
于 2014-02-25T19:37:32.897 回答
13

我在这里有点晚了,但我认为这也是一个非常简洁的解决方案:

_.invoke(this.collection.toArray(), 'destroy');
于 2013-07-18T00:46:21.770 回答
1

捎带肖恩安德森的答案。可以直接访问骨干集合数组,因此您可以这样做。

_.invoke(this.collection.models, 'destroy');

或者只是reset()在没有参数的情况下调用集合,该集合destroy中模型上的方法将被双向触发。

this.collection.reset(); 

http://backbonejs.org/#Collection-models

于 2013-12-25T23:44:08.073 回答
0

这行得通,有点惊讶我不能为此使用下划线。

for (var i = this.collection.length - 1; i >= 0; i--)
    this.collection.at(i).destroy();
于 2012-06-02T00:45:50.997 回答
0

你不需要下划线和for循环。

this.collection.slice().forEach(element => element.destroy());
于 2019-07-30T07:43:52.200 回答
0

我更喜欢这种方法,特别是如果您需要在每个模型上调用destroy,清除集合,而不是调用DELETE服务器。删除id或任何idAttribute设置是允许的。

var myCollection = new Backbone.Collection();
var models = myCollection.remove(myCollection.models);
_.each(models, function(model) {
  model.set('id', null); // hack to ensure no DELETE is sent to server
  model.destroy();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>

于 2016-06-29T06:30:03.597 回答