web-dev-qa-db-de.com

The cleanste way, to every model in a collection in backbone to zerstören?

Beim ersten Versuch habe ich geschrieben

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

Dies funktioniert nicht, da es ConcurrentModificationException in Java ähnelt, wo alle anderen Elemente entfernt werden.

Ich habe versucht, ein "remove" -Ereignis am Modell zu binden, um sich selbst wie vorgeschlagen zu zerstören. Ein Backbone-Modell in einer Sammlung in einem Schritt zerstören? , aber dies löst 2 Löschanforderungen aus, wenn ich destroy für ein Modell aufrufe, das zu einer Sammlung gehört.

Ich habe mir das Dokument mit dem Unterstrich angesehen und kann keine each() -Variante finden, die rückwärts durchläuft und das Problem des Entfernens aller Elemente lösen würde.

Was würden Sie als die sauberste Art und Weise vorschlagen, eine Sammlung von Modellen zu zerstören?

Vielen Dank

17
Henry

Sie könnten auch eine gute, altmodische verwenden pop an Ort und Stelle zerstören:

var model;

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

Ich bin vor kurzem auch auf dieses Problem gestoßen. Es sieht so aus, als hätten Sie es gelöst, aber ich denke, eine detailliertere Erklärung könnte auch für andere hilfreich sein, die sich genau fragen, warum dies der Fall ist.

Also, was ist wirklich los?

Angenommen, wir haben eine Sammlung (Bibliothek) von Modellen (Büchern).

Zum Beispiel:

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

Lassen Sie uns nun alle Bücher nach Ihrem ersten Ansatz durchgehen und löschen:

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

each ist eine Unterstreichungsmethode, die in die Backbone-Auflistung gemischt ist. Es verwendet den Sammlungsverweis auf seine Modelle (library.models) als Standardargument für diese verschiedenen Unterstrich-Sammlungsmethoden. Okay, sicher. Das hört sich vernünftig an.

Wenn das Modell nun destroy aufruft, löst es ein "destroy" -Ereignis für die Sammlung aus , das dann seinen Verweis auf das Modell entfernen . In remove werden Sie Folgendes bemerken:

this.models.splice(index, 1);

Wenn Sie mit splice nicht vertraut sind, lesen Sie das doc . Wenn ja, können Sie möglicherweise erkennen, warum dies problematisch ist.

Nur um zu demonstrieren:

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

Dies führt dann dazu, dass die each-Schleife Elemente überspringt, da der Verweis auf die Modellobjekte über models dynamisch geändert wird!

Wenn Sie JavaScript <1.6 verwenden, tritt möglicherweise der folgende Fehler auf:

Uncaught TypeError: Cannot call method 'destroy' of undefined

Dies liegt daran, dass in der Unterstreichungsimplementierung von each auf die eigene Implementierung zurückgegriffen wird, wenn die native forEach fehlt. Es wird beanstandet, wenn Sie ein Element während der Iteration löschen, da weiterhin versucht wird, auf nicht vorhandene Elemente zuzugreifen.

Wenn die native forEach existieren würde, würde sie stattdessen verwendet und Sie würden überhaupt keinen Fehler erhalten!

Warum? Nach dem doc :

Wenn vorhandene Elemente des Arrays geändert oder gelöscht werden, entspricht der an den Rückruf übergebene Wert dem Wert zum Zeitpunkt, zu dem forEach sie besucht. Elemente, die gelöscht werden, werden nicht besucht .

Also, was ist die Lösung?

Verwenden Sie collection.each nicht, wenn Sie Modelle aus der Sammlung löschen. Verwenden Sie eine Methode, mit der Sie an einem neuen Array arbeiten können, das die Verweise auf die Modelle enthält. Eine Möglichkeit besteht darin, den Unterstrich clone-Methode zu verwenden.

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

Ich bin hier ein bisschen spät dran, aber ich denke, das ist auch eine ziemlich prägnante Lösung:

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

Huckepack auf Sean Anderson Antwort. Es gibt einen direkten Zugriff auf das Backbone-Auflistungsarray, sodass Sie dies so tun können.

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

Oder rufen Sie einfach reset() für die Sammlung ohne Parameter auf. destroy metod für die Modelle in dieser Sammlung wird ausgelöst.

this.collection.reset(); 

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

1
Ivan V.

Ich bevorzuge diese Methode, insbesondere wenn Sie destroy für jedes Modell aufrufen müssen, die Auflistung löschen und DELETE nicht für den Server aufrufen müssen. Das Entfernen von id oder was auch immer idAttribute eingestellt ist, ermöglicht dies.

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>
0
earl3s

Das funktioniert, ein bisschen überrascht, dass ich den Unterstrich dafür nicht verwenden kann.

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

Sie brauchen dafür keinen Unterstrich und keine for -Schleife.

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