backbone.js - source - ¿La forma más limpia de destruir todos los modelos de una colección en Backbone?
backbone significado (6)
En el primer intento escribí
this.collection.each(function(element){
element.destroy();
});
Esto no funciona, porque es similar a ConcurrentModificationException
en Java, donde se eliminan todos los demás elementos.
Intenté vincular el evento "eliminar" en el modelo para destruirse a sí mismo como se sugiere ¿ Destruir un modelo de red troncal en una colección en un solo paso? , pero esto activará 2 solicitudes de eliminación si llamo a destroy en un modelo que pertenece a una colección.
Miré el documento de subrayado y no puedo ver una variante de each()
que se desplaza hacia atrás, lo que resolvería la eliminación de cada problema de elementos.
¿Qué sugerirías como la forma más limpia de destruir una colección de modelos?
Gracias
Esto funciona, algo sorprendido de que no pueda usar el guión bajo para esto.
for (var i = this.collection.length - 1; i >= 0; i--)
this.collection.at(i).destroy();
Estoy un poco tarde aquí, pero creo que esta es una solución bastante breve, también:
_.invoke(this.collection.toArray(), ''destroy'');
Piggybacking en la respuesta de Sean Anderson. Hay un acceso directo a la matriz de la colección troncal, por lo que podría hacerlo de esta manera.
_.invoke(this.collection.models, ''destroy'');
O simplemente llame a reset()
en la colección sin parámetros, destroy
método en los modelos en esa colección se activará dos veces.
this.collection.reset();
Prefiero este método, especialmente si necesita llamar a destroy en cada modelo, borrar la colección y no llamar DELETE
al servidor. Eliminar idAttribute
es lo que lo permite.
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>
Recientemente me encontré con este problema también. Parece que lo resolvió, pero creo que una explicación más detallada también podría ser útil para otros que se preguntan exactamente por qué ocurre esto.
Entonces, ¿qué está pasando realmente?
Supongamos que tenemos una colección (biblioteca) de modelos (libros).
Por ejemplo:
console.log(library.models); // [object, object, object, object]
Ahora, veamos y borre todos los libros usando su enfoque inicial:
library.each(function(model) {
model.destroy();
});
each
es un método de subrayado que se mezcla con la colección Backbone . Utiliza la referencia de colecciones a sus modelos ( library.models
) como argumento predeterminado para estos diversos métodos de colección de guión bajo. Bien, seguro. Eso suena razonable.
Ahora, cuando el modelo llama a destroy
, también activa un evento "destroy" en la colección , que luego eliminará su referencia al modelo . Dentro de remove
, te darás cuenta de esto:
this.models.splice(index, 1);
Si no está familiarizado con el splice
, consulte el doc . Si es así, puede ver por qué esto es problemático.
Sólo para demostrar:
var list = [1,2];
list.splice(0,1); // list is now [2]
¡Esto hará que each
bucle salte elementos porque la referencia a los objetos del modelo a través de los models
se está modificando dinámicamente!
Ahora, si estás usando JavaScript <1.6, entonces puedes encontrarte con este error:
Uncaught TypeError: Cannot call method ''destroy'' of undefined
Esto se debe a que en la implementación de subrayado de each
, se forEach
a su propia implementación si falta el forEach
nativo. Se queja si elimina un elemento a mitad de la iteración porque todavía intenta acceder a elementos no existentes.
Si forEach
el forEach
nativo, entonces se usaría en su lugar y no obtendrías ningún error.
¿Por qué? Según el doc .
Si los elementos existentes de la matriz se modifican, o se eliminan, su valor pasado a callback será el valor en el momento en que cada uno los visite; Los elementos que se eliminan no se visitan .
Entonces, ¿cuál es la solución?
No uses collection.each
si estás eliminando modelos de la colección. Use un método que le permita trabajar en una nueva matriz que contenga las referencias a los modelos. Una forma es utilizar el método de clone
guión bajo.
_.each(_.clone(collection.models), function(model) {
model.destroy();
});
También podrías usar un buen, viejo estilo. popular destruir en el lugar:
var model;
while (model = this.collection.first()) {
model.destroy();
}