Je souhaite surveiller les modifications apportées à un dictionnaire, mais pour une raison quelconque, le rappel de surveillance n'est pas appelé.
Voici un contrôleur que j'utilise:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
});
}
Voici violon .
Je m'attends à ce que $ watch callback soit déclenché à chaque changement de nom ou de nom de famille, mais cela ne se produit pas.
Quelle est la bonne façon de le faire?
Appelez $watch
avec true
comme troisième argument:
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
}, true);
Par défaut, lors de la comparaison de deux objets complexes en JavaScript, l’égalité "référence" sera vérifiée, ce qui demande si les deux objets font référence à la même chose, plutôt que l’égalité "valeur", qui vérifie si les valeurs de toutes les objets sont égaux.
Selon la documentation Angular , le troisième paramètre est pour objectEquality
:
Lorsque
objectEquality == true
, l'inégalité de watchExpression est déterminée conformément à la fonctionangular.equals
. Pour enregistrer la valeur de l'objet en vue d'une comparaison ultérieure, la fonctionangular.copy
est utilisée. Cela signifie donc que regarder des objets complexes aura des implications négatives sur la mémoire et les performances.
L'objet form
ne change pas, seule la propriété name
est
mis à jour violon
function MyController($scope) {
$scope.form = {
name: 'my name',
}
$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
console.log('changed');
$scope.changeCount++;
});
}
Petit astuce performance si quelqu'un a un type de service de banque de données avec des paires clé -> valeur:
Si vous disposez d'un service appelé dataStore, vous pouvez mettre à jour un horodatage chaque fois que votre objet de données volumineuses change .
app.factory('dataStore', function () {
var store = { data: [], change: [] };
// when storing the data, updating the timestamp
store.setData = function(key, data){
store.data[key] = data;
store.setChange(key);
}
// get the change to watch
store.getChange = function(key){
return store.change[key];
}
// set the change
store.setChange = function(key){
store.change[key] = new Date().getTime();
}
});
Et dans une directive, vous ne faites que regarder l'horodatage pour changer
app.directive("myDir", function ($scope, dataStore) {
$scope.dataStore = dataStore;
$scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
if(newVal !== oldVal && newVal){
// Data changed
}
});
});
La raison pour laquelle votre code ne fonctionne pas est que $watch
par défaut vérifie les références. Donc, en un mot, assurez-vous que l'objet qui lui est transmis est un nouvel objet. Mais dans votre cas, vous ne faites que modifier une propriété de l’objet formulaire qui n’en crée pas une nouvelle. Pour que cela fonctionne, vous pouvez passer true
en tant que troisième paramètre.
$scope.$watch('form', function(newVal, oldVal){
console.log('invoked');
}, true);
Cela fonctionnera, mais vous pouvez utiliser $ watchCollection qui sera plus efficace que $ watch car $watchCollection
surveillera les propriétés superficielles de l’objet formulaire. Par exemple.
$scope.$watchCollection('form', function (newVal, oldVal) {
console.log(newVal, oldVal);
});
Essaye ça:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
function track(newValue, oldValue, scope) {
console.log('changed');
};
$scope.$watch('form.name', track);
}
Pour quiconque souhaitait voir un changement d'objet dans un tableau d'objets, cela semblait fonctionner pour moi (contrairement aux autres solutions de cette page):
function MyController($scope) {
$scope.array = [
data1: {
name: 'name',
surname: 'surname'
},
data2: {
name: 'name',
surname: 'surname'
},
]
$scope.$watch(function() {
return $scope.data,
function(newVal, oldVal){
console.log(newVal, oldVal);
}, true);