Descrivendo il funzionamento interno di Angular abbiamo parlato dei watch come di un meccanismo per monitorare il variare dei valori di una variabile di scope. Angular crea un watch per ogni variabile utilizzata nella view senza il nostro intervento. Abbiamo tuttavia anche la possibilità di creare manualmente i watch per la nostra applicazione.
Supponiamo di avere il seguente codice:
Numero: <input type="text" ng-model="numero"></br>
<button ng-click="doppio = numero * 2">Raddoppia</button></br>
<span>{{doppio}}</span>
Si tratta della versione Angular-style dell'esempio visto precedentemente. Qui abbiamo sfruttato il più possibile la possibilità di scrivere delle espressioni direttamente nella view. Come possiamo fare se abbiamo bisogno di effettuare una specifica attività quando cambia il valore della variabile doppio
? In questo caso possiamo creare un watch sulla variabile come mostrato nell'esempio seguente:
$scope.$watch("doppio", function(newValue, oldValue) {
if (newValue != oldValue)
alert("Raddoppio in " + newValue);
});
Nel controller associato alla view definiamo il watch utilizzando il metodo $watch()
dello scope corrente. Il metodo prende come parametri:
- una stringa che rappresenta il nome della variabile da monitorare;
- la funzione da eseguire quando cambia il valore della variabile. Alla funzione vengono passati il nuovo ed il vecchio valore, in modo che possiamo effettuare eventuali confronti.
Nel nostro caso visualizziamo un alert
che avvisa del cambio di valore, ma naturalmente in una situazione reale possiamo eseguire attività un po' più concrete, come ad esempio inviare un'informazione al server.
La funzione associata al watch sarà eseguita ogni volta che il valore della variabile doppio
cambierà rispetto al valore precedente. C'è però un'eccezione: la funzione viene eseguita anche all'avvio del controller. In questo caso non c'è alcuna variazione del valore, per cui il controllo che il nuovo valore sia diverso dal vecchio risulta fondamentale se non vogliamo avere falsi avvisi.
Consideriamo ora un esempio leggermente diverso:
<div ng-controller="myCtrl2">
Nome: <input type="text" ng-model="persona.nome"></br>
</div>
...
.controller("myCtrl2", function($scope) {
$scope.persona = { nome: "Mario"};
$scope.$watch("persona", function(newValue, oldValue) {
if (newValue != oldValue)
alert("Il nuovo valore è " + newValue);
});
});
In questo caso abbiamo definito un oggetto persona
e diamo la possibilità all'utente di cambiare la proprietà nome
tramite una casella di testo. Purtroppo cambiando il valore della casella di testo non avviene quanto atteso. Il watch non viene attivato e di conseguenza la funzione associata non viene eseguita.
Il motivo risiede nel fatto che, nel caso di oggetti, un watch confronta i riferimenti, cioè viene considerata variazione di valore solo se la variabile punta ad un nuovo oggetto.
Nel nostro caso la variabile persona fa riferimento sempre allo stesso oggetto, anche se è stato modificato il valore della proprietà nome
, quindi il watch non rileva alcuna variazione. Per catturare le variazioni dei valori di un oggetto è necessario specificare un terzo parametro booleano nel metodo $watch()
:
$scope.$watch("persona", function(newValue, oldValue) {
if (newValue != oldValue)
alert("Il nuovo valore è " + newValue.nome);
}, true);
Indicando il valore true
come terzo parametro di $watch()
avremo la possibilità di intercettare la variazione dei valori delle proprietà di un oggetto.