Dans AngularJS, j'ai une directive qui surveille une variable de portée. Lorsque la variable contient certaines données, je dois modifier un peu cette variable. Le problème est que lorsque je modifie la variable que mon $watch
est à nouveau déclenché. Je me retrouve donc dans une boucle continue.
scope.$watch('someVar', function(newValue, oldValue) {
console.log(newValue);
scope.someVar = [Do something with someVar];
});
Cela continue de déclencher $watch
encore une fois, ce qui est logique. Mais j'ai besoin d'un moyen de changer la variable surveillée. Y a-t-il un moyen de faire cela?
Lorsqu'une variable est surveillée pour les modifications à l'aide de $scope.$watch
, angular vérifie si la référence a changé. Si c'est le cas, alors le $watch
le gestionnaire est exécuté pour mettre à jour la vue.
Si vous prévoyez de changer la variable de portée dans le gestionnaire $ watch, cela déclenchera une boucle infinie $ digest car la référence de variable de portée change chaque fois qu'elle est appelée.
L'astuce pour contourner le problème du résumé infini est de préserver la référence à l'intérieur de votre $watch
gestionnaire utilisant angular.copy ( docs ):
scope.$watch('someVar', function(newValue, oldValue) {
console.log(newValue);
var someVar = [Do something with someVar];
// angular copy will preserve the reference of $scope.someVar
// so it will not trigger another digest
angular.copy(someVar, $scope.someVar);
});
Remarque: cette astuce ne fonctionne que pour les références d'objet. Cela ne fonctionnera pas avec les primitives.
En général, ce n'est pas une bonne idée de mettre à jour un $watched
variable dans sa propre $watch
auditeur. Cependant, parfois, cela peut être inévitable.
Utilisation de la fonction interne si condition pour éviter la boucle continue
scope.$watch('someVar', function(newValue, oldValue) {
if(newValue!==oldValue) {
console.log(newValue);
scope.someVar = [Do something with someVar];
}
});
C'est ainsi que fonctionne la vérification de la saleté. Chaque fois que quelque chose sur le $scope
changes Angular fera défiler tout ce qui est attaché à la portée et continuera de le faire jusqu'à ce qu'il n'y ait plus de changements.
Si vous voulez faire quelque chose comme ça, vous devrez vous assurer que votre $watch
la fonction est idempotente. Vous devrez examiner à la fois newValue
et oldValue
et déterminer si vous avez déjà appliqué les modifications à votre variable dans ce $digest
boucle. La façon dont vous pouvez faire cela dépend un peu du type de modifications que vous apportez à someVar
.
D'une manière générale, changer une variable surveillée dans une fonction de surveillance n'est malheureusement pas une bonne idée.
vous pouvez le gérer en utilisant une variable bool
$scope.someVarChanged = false;
scope.$watch('someVar', function(newValue, oldValue) {
console.log(newValue);
$scope.someVarChanged = !$scope.someVarChanged!;
if($scope.someVarChanged) {
scope.someVar = [Do something with someVar];
}
});
oui vous pouvez l'annuler comme ça
var wathcer = scope.$watch('someVar', function(newValue, oldValue) {
console.log(newValue);
scope.someVar = [Do something with someVar];
});
wathcer(); // clear the watch