Au premier essai j'ai écrit
this.collection.each(function(element){
element.destroy();
});
Cela ne fonctionne pas, car il est similaire à ConcurrentModificationException
en Java, où tous les autres éléments sont supprimés.
J'ai essayé de lier l'événement "remove" au modèle pour se détruire, comme suggéré. Détruire un modèle de colonne vertébrale dans une collection en une seule étape? , mais cela déclenchera 2 demandes de suppression si j'appelle détruire sur un modèle appartenant à une collection.
J'ai consulté le document de soulignement et je ne peux pas voir une variante each()
qui effectue une boucle en arrière, ce qui résoudrait le problème de la suppression de chaque élément.
Que suggéreriez-vous comme le moyen le plus propre de détruire une collection de modèles?
Merci
Vous pouvez également utiliser un bon vieux pop détruire en place:
var model;
while (model = this.collection.first()) {
model.destroy();
}
J'ai récemment rencontré ce problème aussi. Il semble que vous ayez résolu le problème, mais je pense qu'une explication plus détaillée pourrait également être utile pour les autres qui se demandent exactement pourquoi cela se produit.
Supposons que nous ayons une collection (bibliothèque) de modèles (livres).
Par exemple:
console.log(library.models); // [object, object, object, object]
Maintenant, passons en revue et supprimons tous les livres en utilisant votre approche initiale:
library.each(function(model) {
model.destroy();
});
each
est une méthode de soulignement qui est mélangée à la collection Backbone . Il utilise la référence des collections à ses modèles (library.models
) comme argument par défaut pour ces différentes méthodes de collecte de soulignement. Ok, bien sur. Cela semble raisonnable.
Maintenant, lorsque le modèle appelle destroy
, il déclenche également un événement "destroy" sur la collection , qui _ supprimera sa référence au modèle . Dans remove
, vous remarquerez ceci:
this.models.splice(index, 1);
Si vous ne connaissez pas splice
, reportez-vous à la doc . Si vous êtes, vous pouvez voir pourquoi c'est problématique.
Juste pour démontrer:
var list = [1,2];
list.splice(0,1); // list is now [2]
La boucle each
ignorera alors les éléments car sa référence aux objets du modèle via models
est modifiée de façon dynamique!
Maintenant, si vous utilisez JavaScript <1.6, alors vous pouvez rencontrer cette erreur:
Uncaught TypeError: Cannot call method 'destroy' of undefined
En effet, dans l'implémentation de soulignement de each
, il revient à sa propre implémentation si la variable native forEach
est manquante. Il se plaint si vous supprimez un élément à mi-itération car il essaie toujours d'accéder à des éléments inexistants.
Si la variable forEach
native existait, elle serait utilisée à la place et vous n'obtiendriez pas d'erreur du tout!
Pourquoi? Selon le doc :
Si des éléments existants du tableau sont modifiés ou supprimés, leur valeur transmise à callback sera la valeur au moment où chacun les visite; Les éléments supprimés ne sont pas visités .
Alors, quelle est la solution?
N'utilisez pas collection.each
si vous supprimez des modèles de la collection. Utilisez une méthode qui vous permettra de travailler sur un nouveau tableau contenant les références aux modèles. Une solution consiste à utiliser le trait de soulignement méthode clone
.
_.each(_.clone(collection.models), function(model) {
model.destroy();
});
Je suis un peu en retard, mais je pense que c'est aussi une solution assez succincte:
_.invoke(this.collection.toArray(), 'destroy');
Piggybacking sur la réponse de Sean Anderson. Il y a un accès direct au tableau de collecte du backbone, vous pouvez donc le faire comme ceci.
_.invoke(this.collection.models, 'destroy');
Ou appelez simplement reset()
sur la collection sans paramètres, destroy
metod sur les modèles de cette collection sera déclenché.
this.collection.reset();
Je préfère cette méthode, en particulier si vous devez appeler destroy sur chaque modèle, effacez la collection et n'appelez pas DELETE
au serveur. La suppression de id
ou de ce que idAttribute
est défini est ce qui le permet.
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>
Cela fonctionne, un peu surpris que je ne puisse pas utiliser de trait de soulignement pour cela.
for (var i = this.collection.length - 1; i >= 0; i--)
this.collection.at(i).destroy();