457 votes

Surveiller plusieurs attributs de $scope

Existe-t-il un moyen de s'abonner à des événements sur plusieurs objets en utilisant la fonction $watch

Par exemple

$scope.$watch('item1, item2', function () { });

603voto

Paolo Moretti Points 9519

À partir d'AngularJS 1.3, il y a une nouvelle méthode appelée $watchGroup pour l'observation d'un ensemble d'expressions.

$scope.foo = 'foo';
$scope.bar = 'bar';

$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
  // newValues array contains the current values of the watch expressions
  // with the indexes matching those of the watchExpression array
  // i.e.
  // newValues[0] -> $scope.foo 
  // and 
  // newValues[1] -> $scope.bar 
});

7 votes

Quelle est la différence avec $watchCollection('[a, b]') ? ?

30 votes

La différence est que vous pouvez utiliser un véritable tableau au lieu d'une chaîne qui ressemble à un tableau.

2 votes

J'ai eu un problème similaire mais en utilisant le motif controllerAs. Dans mon cas, la solution consistait à ajouter aux variables le nom du contrôleur : $scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...

292voto

Răzvan Panda Points 6800

À partir d'AngularJS 1.1.4 vous pouvez utiliser $watchCollection :

$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
    // do stuff here
    // newValues and oldValues contain the new and respectively old value
    // of the observed collection array
});

Exemple de Plunker aquí

Documentation aquí

109 votes

Notez que le premier paramètre est no un tableau. C'est une chaîne qui ressemble à un tableau.

1 votes

Merci pour cela. si cela fonctionne pour moi, je vous donnerai mille pièces d'or - virtuelles, bien sûr :)

5 votes

Pour être clair (il m'a fallu quelques minutes pour le réaliser) $watchCollection est destiné à recevoir un objet et à surveiller les changements apportés aux propriétés de l'objet, alors que $watchGroup est destiné à fournir un tableau de propriétés individuelles à surveiller pour les changements. Légèrement différent pour aborder des problèmes similaires mais différents. Ouf !

118voto

Andy Joslin Points 23231

$watch Le premier paramètre peut également être une fonction.

$scope.$watch(function watchBothItems() {
  return itemsCombinedValue();
}, function whenItemsChange() {
  //stuff
});

Si vos deux valeurs combinées sont simples, le premier paramètre est juste une expression angulaire normalement. Par exemple, firstName et lastName :

$scope.$watch('firstName + lastName', function() {
  //stuff
});

8 votes

Il s'agit d'un cas d'utilisation qui mérite d'être inclus par défaut dans le cadre de travail. Même une propriété calculée aussi simple que fullName = firstName + " " + lastName nécessite de passer une fonction comme premier argument (plutôt qu'une simple expression comme 'firstName, lastName' ). Angular est TELLEMENT puissant, mais il y a certains domaines où il peut être énormément plus convivial pour les développeurs d'une manière qui ne compromet pas (semble-t-il) les performances ou les principes de conception.

4 votes

Eh bien $watch prend juste une expression angulaire, qui est évaluée sur la portée sur laquelle elle est appelée. Donc vous pourriez faire $scope.$watch('firstName + lastName', function() {...}) . Vous pourriez aussi faire deux montres : function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged); . J'ai ajouté le cas simple à la réponse.

0 votes

Le plus dans 'firstName + lastName' est une concaténation de chaînes de caractères. Angular vérifie donc simplement si le résultat de la concaténation est différent maintenant.

72voto

Karl Zilles Points 3549

Voici une solution très similaire à votre pseudo-code original qui fonctionne réellement :

$scope.$watch('[item1, item2] | json', function () { });

EDIT : Ok, je pense que c'est encore mieux :

$scope.$watch('[item1, item2]', function () { }, true);

En gros, nous sautons l'étape du json, ce qui semblait stupide au départ, mais ça ne marchait pas sans. La clé est le 3ème paramètre souvent omis qui active l'égalité des objets par opposition à l'égalité des références. Ainsi, les comparaisons entre les objets de notre tableau créé fonctionnent correctement.

0 votes

J'ai eu une question similaire. Et voici la réponse correcte pour moi.

0 votes

Les deux ont un léger surcoût de performance si les éléments dans l'expression du tableau ne sont pas des types simples.

0 votes

C'est vrai il fait une comparaison approfondie des objets composants. Ce qui n'est pas forcément ce que vous voulez. Voir la réponse actuellement approuvée pour une version utilisant angular moderne qui ne fait pas de comparaison en profondeur.

12voto

Erik Aigner Points 7182

Pourquoi ne pas simplement l'envelopper dans un forEach ?

angular.forEach(['a', 'b', 'c'], function (key) {
  scope.$watch(key, function (v) {
    changed();
  });
});

C'est à peu près la même surcharge que de fournir une fonction pour la valeur combinée, sans avoir à se soucier de la composition de la valeur .

0 votes

Dans ce cas, log() serait exécuté plusieurs fois, n'est-ce pas ? Je pense que dans le cas de fonctions $watch imbriquées, ce ne serait pas le cas. Et il ne devrait pas dans la solution pour surveiller plusieurs attributs à la fois.

0 votes

Non, le journal n'est exécuté qu'une fois par changement et par propriété surveillée. Pourquoi serait-il invoqué plusieurs fois ?

0 votes

C'est vrai, je veux dire que ça ne marcherait pas bien si on voulait tous les regarder simultanément.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X