Самый чистый способ уничтожить каждую модель в коллекции в магистрали?

С первой попытки я написал

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

Это не работает, потому что он похож на ConcurrentModificationException на Java, где удаляются все остальные элементы.

Я попробовал привязать "удалить" событие на модели, чтобы уничтожить себя, как было предложено Уничтожение модели Backbone в коллекции за один шаг?, но это приведет к удалению 2 delete запросы, если я вызываю destroy на модели, принадлежащей коллекции.

Я посмотрел на underscore doc и не вижу вариант each(), который зацикливается назад, что решит проблему удаления каждого элемента.

Что бы вы предложили как самый чистый способ уничтожить коллекцию моделей?

Спасибо

Ответы

Ответ 1

Вы также можете использовать хороший, оловянный pop destroy-in-place:

var model;

while (model = this.collection.first()) {
  model.destroy();
}

Ответ 2

Недавно я столкнулся с этой проблемой. Похоже, вы разрешили его, но я думаю, что более подробное объяснение может также быть полезным для других, которые задаются вопросом, почему именно это происходит.

Итак, что на самом деле происходит?

Предположим, что у нас есть коллекция (библиотека) моделей (книг).

Например:

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

Теперь давайте рассмотрим и удалим все книги, используя ваш первоначальный подход:

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

each - это метод подчеркивания, который перемещается в коллекцию Backbone. Он использует ссылку на коллекции для своих моделей (library.models) в качестве аргумента по умолчанию для этих различных методов подбора подчеркивания. Да конечно. Это звучит разумно.

Теперь, когда модель вызывает destroy, она запускает событие "уничтожить" в коллекции, а затем удалить ссылку на модель. Внутри remove вы заметите следующее:

this.models.splice(index, 1);

Если вы не знакомы с splice, см. doc. Если да, то вы можете понять, почему это проблематично.

Просто чтобы продемонстрировать:

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

Это приведет к тому, что цикл each пропустит элементы, потому что его ссылка на объекты модели через models динамически изменяется!

Теперь, если вы используете JavaScript < 1.6, то вы можете столкнуться с этой ошибкой:

Uncaught TypeError: Cannot call method 'destroy' of undefined

Это связано с тем, что в реализации подчёркивания each в нижней подчеркивании он возвращается к своей собственной реализации, если отсутствует родной forEach. Он жалуется, что вы удаляете среднюю итерацию элемента, потому что она по-прежнему пытается получить доступ к несуществующим элементам.

Если нативный forEach существует, тогда он будет использоваться вместо этого, и вы не получите ошибку вообще!

Почему? Согласно doc:

Если существующие элементы массива будут изменены или удалены, их значение, переданное обратному вызову, будет значением в момент, когда каждый посетит их; удаленные элементы не посещаются.

Итак, какое решение?

Не используйте collection.each, если вы удаляете модели из коллекции. Используйте метод, который позволит вам работать с новым массивом, содержащим ссылки на модели. Один из способов - использовать метод подчеркивания clone.

_.each(_.clone(collection.models), function(model) {
  model.destroy();
});

Ответ 3

Я немного опоздал, но я думаю, что это тоже довольно сжатое решение:

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

Ответ 4

Ответ на вопрос Шона Андерсона. Существует прямой доступ к массиву сборных матриц, поэтому вы можете сделать это следующим образом.

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

Или просто вызовите reset() в коллекции без параметров, метод destroy на моделях в этой коллекции будет активирован bi.

this.collection.reset(); 

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

Ответ 5

Это работает, удивляясь, что я не могу использовать подчеркивание для этого.

for (var i = this.collection.length - 1; i >= 0; i--)
    this.collection.at(i).destroy();

Ответ 6

Я предпочитаю этот метод, особенно если вам нужно вызвать 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>

Ответ 7

Для этого вам не нужно подчеркивание и цикл for.

this.collection.slice().forEach(element => element.destroy());