2013-03-12 12 views
52

Sto cercando di capire perché il mio $watch non viene attivato. Si tratta di un frammento dal controller relativo:

$scope.$watch('tasks', function (newValue, oldValue) { 
    //do some stuff 
    //only enters here once 
    //newValue and oldValue are equal at that point 
}); 

$scope.tasks = tasksService.tasks(); 

$scope.addTask = function (taskCreationString) { 
    tasksService.addTask(taskCreationString);//modifies tasks array 
}; 

Sul mio punto di vista, tasks è chiaramente in fase di aggiornamento in modo corretto, come ho legato la sua lunghezza in questo modo:

<span>There are {{tasks.length}} total tasks</span> 

Che cosa mi manca?

+0

Sembra che questo problema vale anche per guardare gli oggetti. Invece, devi guardare una particolare proprietà. – VSO

risposta

131

Prova $watch('tasks.length', ...) o $watch('tasks', function(...) { ... }, true).

Per impostazione predefinita, $watch non verifica l'uguaglianza dell'oggetto, ma solo per riferimento. Quindi, $watch('tasks', ...) restituirà sempre lo stesso riferimento di array, che non sta cambiando.

Aggiornamento: v1.1.4 angolare aggiunge un metodo $watchCollection() per gestire questo caso:

Shallow guarda le proprietà di un oggetto e incendi ogniqualvolta qualsiasi delle proprietà cambia (per array questo implica monitorando l'array oggetti, per le mappe oggetto ciò implica la visione delle proprietà). Se viene rilevata una modifica, viene attivato il callback listener.

+0

grazie per la spiegazione, ho passato ore non sapendo questo – asumaran

+3

Questo alleviato molto dolore e tristezza, grazie! –

+0

grazie. mi ha aiutato oggi – VeteranLK

13

Risposta molto buona da @Mark. Oltre alla sua risposta, c'è una funzionalità importante della funzione $watch di cui dovresti essere a conoscenza.

Con la dichiarazione $watch funzione come segue:

$watch(watch_expression, listener, objectEquality) 

La funzione $watchascoltatore viene chiamato solo quando il valore della corrente orologio espressione (nel tuo caso è 'tasks') e la chiamata precedente a l'espressione dell'orologio non è uguale. Angolare salva il valore dell'oggetto per un confronto successivo. Per questo motivo, la visione di opzioni complesse avrà implicazioni di memoria e prestazioni svantaggiose. Fondamentalmente il più semplice espressione orologio e meglio è.

+5

+1. Menzionerò (per completezza) che la funzione listener viene chiamata anche una volta inizialmente per inizializzare l'osservatore. Questo deve accadere _anche se 'watch_expression' non è cambiato_. –

+0

sì ... copiato il documento. https://docs.angularjs.org/api/ng/type/$rootScope.Scope – hupseb

5

Vorrei consigliamo di provare

$scope.$watch('tasks | json', ...) 

che cattura tutte le modifiche alla matrice tasks, in quanto mette a confronto l'array serializzato come stringa.

+3

Come nota cautelativa, questa soluzione implica la serializzazione su JSON in ogni ciclo di digest, non ottimale per le prestazioni (in particolare se l'oggetto è un complesso uno o un lungo array). Funzionerà *, ma è un po 'un' mazza da spaccare '. – decates

+0

un piccolo test delle prestazioni per diverse dimensioni di oggetti sarebbe interessante. – abimelex

+0

Questo mi ha impostato sulla strada giusta per risolvere lo stesso problema con gli oggetti. – VSO

2

Per uno matrici tridimensionali è possibile utilizzare $watchCollection

$scope.names = ['igor', 'matias', 'misko', 'james']; 
$scope.dataCount = 4; 

$scope.$watchCollection('names', function(newNames, oldNames) { 
    $scope.dataCount = newNames.length; 
}); 
Problemi correlati