this.each неправильно перебирает коллекцию

Я только начал использовать backbone.js и добавляю некоторые базовые методы для расширения коллекции, позволяющие мне перебирать коллекцию и сохранять все модели, а также перебирать коллекцию для уничтожения всех моделей. Я понимаю, что массовые обновления не являются RESTful, но я обновляю только локальное хранилище, поэтому не думал, что будет проблемой делать несколько обновлений.

В моем базовом приложении в коллекции 9 моделей. Когда я вызываю collection.saveModels(), он правильно регистрирует длину коллекции и правильно сохраняет все модели.

Когда я вызываю collection.deleteModels(), он правильно регистрирует длину коллекции, но пропускает каждую вторую модель (т.е. 2-ю, 4-ю, 6-ю, 8-ю). Каждый раз, когда нажимается удаление, он продолжает удалять только нечетный индексированный элемент, при этом последним удаляемым элементом является 8-й исходный элемент.

Возможно ли, что я неправильно использую каждую функцию, несмотря на то, что она отлично работает при сохранении?

_.extend(Backbone.Collection.prototype, Backbone.Events, {
saveModels  :   function() {
    console.log(this.length);
    this.each(function(model){
        console.log('saving model ' + model.get('name'));
        model.save();
    });
},
deleteModels    :   function() {
    console.log(this.length);
    this.each(function(model){
        console.log('deleting model ' + model.get('name'));
        model.destroy();
    });
}
});

и называются они так: mycollection.saveModels(); и mycollection.deleteModels();

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


person djlumley    schedule 20.06.2011    source источник
comment
в общем, основная проблема с удалением элементов в циклах заключается в том, что он путает текущее положение цикла - длина цикла сокращается, а индекс следующего элемента фактически ссылается на элемент после следующего - например, если вы удаляете первый элемент, следующим индексом для цикла будет второй элемент, но то, что было вторым элементом, теперь является первым, поэтому третий элемент теперь второй - надеюсь, что это имеет смысл   -  person kinakuta    schedule 20.06.2011
comment
Ах, вот оно. Даже не подумал об этом!   -  person djlumley    schedule 20.06.2011
comment
Кажется, вам нужно будет зацикливаться, используя длину, но в любом случае зацикливать назад   -  person mplungjan    schedule 20.06.2011
comment
@kinakuta, ты должен написать это как ответ. я считаю, что это правильно   -  person Pablo Fernandez    schedule 21.06.2011


Ответы (4)


Опубликованный код bradgonesurfing на самом деле не работает, поскольку метод клонирования не возвращает объект подчеркивания. Правильный способ — использовать метод _.chain, который делает каждый метод цепочкой.

_.chain(App.articles.models).clone().each(function(model){
  console.log('deleting model ' + model.get('name'));
  model.destroy();
});
person JamieD    schedule 14.06.2012

Код ниже отлично сработал для меня:

  destroyAll: function (options) {
    while (this.models.length > 0) {
        this.models[0].destroy(options);
    }    
}
person jzon    schedule 21.10.2011
comment
Прошло некоторое время с тех пор, как я использовал backbone, но сейчас собираюсь использовать его в другом проекте - и это выглядит еще более приятным решением - спасибо! - person djlumley; 31.10.2011
comment
Умная! Я везде искал решение. это круто - person Bingy; 19.08.2014

Каждый раз, когда вы вызываете model.destroy(), он удаляет себя из коллекции. Каждый итератор этого не знает. Сделайте что-то вроде следующего.

_.chain(App.articles.models).clone().each(function(model){
  console.log('deleting model ' + model.get('name'));
  model.destroy();
});

Backbone имеет доступ к утилитам underscore.js. Сначала клонируйте массив моделей, затем повторите его, а затем уничтожьте каждую модель. Должно сработать

person bradgonesurfing    schedule 21.06.2011
comment
Ваше решение недействительно, так как клон не возвращает объект подчеркивания, я разместил правильное решение, используя метод цепочки stackoverflow.com/ а/11032971/109995 - person JamieD; 14.06.2012

Это реализация комментария kinakuta's, который я использовал.

destroy_models  :   function() {
    for (var i = this.length - 1; i > -1; i -=1){
        this.getByCid('c'+i).destroy();
    }
}
person djlumley    schedule 30.06.2011
comment
Это совершенно неправильно. Вам не гарантируется, что cid непрерывны от 0..(длина-1). Посмотрите на реализацию getByCid. Он использует поиск по хешу, а не поиск по индексу массива. Мой ответ выше правильный и будет работать во всех случаях. - person bradgonesurfing; 01.07.2011
comment
Я провел немного больше исследований, и похоже, что вы правы, я изначально проголосовал за ваш ответ, но выбрал свой в качестве ответа, потому что он давал ответ на мою проблему ~ - person djlumley; 03.07.2011