2013-08-08 2 views
7

Ho trovato qualcosa di strano in Backbone utilizzando gli eventi di modifica. È con un modello che ha una proprietà Array. E se ho la proprietà spingere un nuovo valore all'interno e riportarlo al modello l'evento di modifica non viene licenziato ...Modifica della proprietà dell'array del modello Backbone e modifica del listener di eventi non sempre attivando

Ecco un esempio completamente documentato:

var TestModel = Backbone.Model.extend({ 
    defaults : { 
     numbers : [] 
    }, 

    initialize : function() { 
     this.on('change:numbers', this.changedEvent); 
    }, 

    changedEvent : function() { 
     console.log('model has changed'); 
    } 
}); 

var oTestModel = new TestModel(); 
    oTestModel.set('numbers', [2, 3, 4]); // change:numbers Event is fired 

var aNumbers = oTestModel.get('numbers'); 
    aNumbers.push(5); 

oTestModel.set('numbers', aNumbers); // change:numbers event is NOT fired BUT WHY??? 

// oTestModel.set('numbers', [2, 3, 4]); 
// If this line is not commented out change:numbers event is also fired 

console.log(oTestModel.toJSON()); // Dumps out [2,3,4,5] Respective [2,3,4] if line above is not commented out 

Thx in anticipo.

risposta

15

Hesson è di circa assolutamente ragione:

array in JavaScript sono trattati come puntatori, in modo da mutare la matrice non cambierà il puntatore e nessun evento "change" viene attivato.

Tuttavia, come una soluzione alternativa (se si utilizza anche underscore.js) si può solo fare:

var aNumbers = _.clone(oTestModel.get('numbers')); 
aNumbers.push(5); 

oTestModel.set('numbers', aNumbers); //Will trigger the changed:numbers event 

Come si è visto nella risposta a questo problema simile: Backbone.js : change not firing on model.change()

Questo duplicherà l'oggetto invece di renderlo un riferimento, tuttavia gli oggetti o le matrici annidate saranno solo riferimenti.

+0

Grazie che mi ha aiutato – Bernhard

+0

Potrebbe esserci un notevole calo di prestazioni usando '_.clone (..)' su un oggetto di grandi dimensioni? – Matthew

+0

Sì, dal momento che stai aggiungendo codice personalizzato per risolvere il problema, aggiungi il codice che attiva l'evento: 'oTestModel.trigger ('cambia: numeri', oTestModel, aNumbers)' – Okneloper

3

Le matrici in JavaScript vengono trattate come puntatori, pertanto la mutazione della matrice non cambia il puntatore e non viene generato alcun evento di "modifica". Invece è necessario impostare un metodo in cui si muta l'array e in questo metodo si attiva il proprio evento personalizzato. Ad esempio:


mutateArray: function() { 
    var numbers = this.get("numbers"); 
    numbers.push(5); 
    this.trigger("mutatedarray"); 
    return this; 
} 

noti che poiché i numeri è un puntatore, sarebbe inutile call set (no pun intended), poiché i numeri è solo un riferimento alla matrice. Quindi è possibile ascoltare le modifiche ascoltando l'evento mutatedarray personalizzato come questo:


this.on("mutatedarray", this.changedEvent, this);