2011-12-13 9 views
5

Uso backbone.js ...L'evento di modifica del modello non si attiva quando si aggiorna un array?

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

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

Questa aggiorna il modello perfettamente, ma non attiva l'evento di modifica. Qualcuno sa perché provando ciò che ho postato?

EDIT:

ho aggiunto questo e si innesca l'evento change:

@model.set 
    test: '' 

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

ho aggiunto questo e non attiva l'evento change:

@model.set 
    test: [] 

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

L'array viene popolato? – Brian

+0

Sì, il modello si aggiorna bene e l'array è correttamente compilato negli attributi dei modelli. – fancy

risposta

6

Il problema è che stai impostando il valore con il valore esistente. Date un'occhiata al codice sorgente:

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

Quando si chiama set ha una clausola di guardia per assicurarsi che non si sta impostando lo stesso valore (per evitare loop di eventi). Nel tuo caso, stai ricevendo l'array, modificandolo e impostandolo nuovamente, il che non attiverà il tuo evento.

Ovviamente, quando si è set test: {}, si tratta di un nuovo elemento con un nuovo oggetto, quindi verrà attivato nuovamente. Se vuoi davvero attivare l'evento, puoi impostarlo su null, quindi impostarlo su una matrice vuota e poi su di nuovo sulla matrice popolata ...

8

La risposta di Brian alla ragione è fantastica!

Voluto presentare un altro modo per ottenere ciò che si desidera invece di annullarlo o clonare l'array.

Basta attivare manualmente il cambio te stesso:

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

Se si dispone di una clonazione di array particolarmente ampia, si tratta di un'opzione scadente.Questo ha molto più senso. –

+0

Con questa soluzione model.changed non verrà aggiornata. – postnerd

1

Potrebbe considerare l'utilizzo di una collezione Backbone al posto di un array, e quindi vincolante per cambiare gli eventi in quella raccolta?

7

Poiché si sta impostando l'oggetto di riferimento, utilizzare _.clone().

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

Dal momento che non sei più utilizzando l'oggetto/array fa riferimento a porsi, che verrà fuoco l'evento di modifica se è cambiato.

6

Un altro modo per passare, quando si cambiano gli oggetti o gli array, consiste nel disattivare la proprietà in modo invisibile prima di impostare il nuovo valore aggiornato. Qualcosa di simile a questo:

(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); 
})(); 

Impostando silent: true quando disinserimento del puntello, l'evento di modifica sarà attiva una sola volta (Quando il metodo set() viene chiamato e la proprietà è stato aggiornato).

Non c'è davvero alcuna differenza tra fare questo o chiamare manualmente l'evento, è solo una questione di preferenze personali.

+2

Preferisco questa opzione - in questo modo Backbone attiva tutte le varianti di evento ('change' e' change: arrayProp') con i parametri predefiniti, in modo da non rompere gli ascoltatori. – joews

Problemi correlati