web-dev-qa-db-fra.com

Regardez la variable et changez-la

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?

20
Vivendi

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.

26
pixelbits

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];
   } 
});
13
chandu

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.

2
ivarni

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];
    }
});
2
harishr

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
1
Narek Mamikonyan