2011-12-13 13 views
5

Uso Backbone.js ...¿El evento de cambio del modelo no se activará al actualizar una matriz?

@model.bind 'change',()-> console.log 'updated' 

addIndex = (index) => 
    array = @model.get('array') 
    array.push index 
    @model.set 
     array: array 

Esto actualiza el modelo perfectamente, pero no activa el evento de cambio. ¿Alguien sabe por qué mirando lo que publiqué?

EDIT:

añadí esto y se dispara el evento de cambio:

@model.set 
    test: '' 

num = 0 
setInterval()=> 
    num++ 
    @model.set 
    test: num 
, 3000 

añadí esto y no activa el evento de cambio:

@model.set 
    test: [] 

num = 0 
setInterval()=> 
    console.log 'testupdate' 
    num++ 
    test = @model.get('test') 
    test.push num 
    @model.set 
     test: test 
, 3000 
+0

es la matriz que se llena? – Brian

+0

Sí, el modelo se actualiza correctamente y la matriz se llena correctamente en los atributos de los modelos. – fancy

Respuesta

6

El problema es que está estableciendo el valor con el valor existente. Tome un vistazo al código fuente:

http://documentcloud.github.com/backbone/docs/backbone.html#section-33

Cuando se llama a set que tiene una cláusula de guardia para asegurarse de que no está configurando el mismo valor (para evitar bucles de eventos). En su caso, está obteniendo la matriz, modificándola y configurándola nuevamente, lo que no activará su evento.

Por supuesto, cuando set test: {}, es un elemento nuevo con un objeto nuevo, por lo que se disparará de nuevo. Si realmente desea desencadenar el evento, puede establecerlo en nulo, luego establecerlo en un conjunto vacío y luego en el conjunto poblado de nuevo ...

8

¡La respuesta de Brian es maravillosa!

Quería presentar otra forma de obtener lo que desea en lugar de anularla o clonarla.

Sólo activar manualmente el cambio sí mismo:

addIndex = (index) => 
    array = @model.get('array') 
    array.push index 
    @model.trigger('change:array',@model, array) 
+0

Si tiene una clonación de matriz particularmente grande, es una opción pobre.Esto tiene mucho más sentido. –

+0

Con esta solución model.changed no se actualizará. – postnerd

1

Podría considerar el uso de una colección Backbone lugar de una matriz, y luego unirse a cambiar los acontecimientos de esa colección?

7

Dado que está configurando el objeto al que se hace referencia, use _.clone().

test = _.clone @model.get('test') 
test.push num 
@model.set test: test 

Dado que ya no estás usando el objeto/matriz de referencia para establecer sí mismo, se disparará el evento de cambio si ha cambiado.

6

Otra forma de hacerlo, al cambiar objetos o matrices, es desarmar silenciosamente la propiedad antes de establecer el nuevo valor actualizado. Algo como esto:

(function() { 
    var arr, model = new Model(); 

    model.set("arrayProp", [1, 2, 3]); 
    arr = model.get("arrayProp"); 
    arr.push(4); 

    model.unset("arrayProp", { silent: true }); 
    model.set("arrayProp", arr); 
})(); 

Al establecer silent: true cuando desarmar la hélice, el evento de cambio sólo se disparará una vez (cuando se llama al método set() y la propiedad se ha actualizado).

No hay realmente una diferencia entre hacer esto o llamar manualmente al evento, es solo una cuestión de preferencia personal.

+2

Prefiero esta opción: de esta forma Backbone activa todas las variantes de eventos ('change' y' change: arrayProp') con parámetros predeterminados, por lo que no romperá ningún oyente. – joews

Cuestiones relacionadas