Watch variable and change it

65,521

Solution 1

When a variable is watched for changes using $scope.$watch, angular checks if the reference has changed. If it has, then the $watch handler is executed to update the view.

If you plan on changing the scope variable within the $watch handler, it will trigger an infinite $digest loop because the scope variable reference changes every time that it is called.

The trick to getting around the infinite digest issue is to preserve the reference inside your $watch handler using 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);

});

Note: This trick only works for object references. It will not work with primitives.

In general, its not a good idea to update a $watched variable within its own $watch listener. However, sometimes it may be unavoidable.

Solution 2

Inside function use if condition to avoide continues for loop

scope.$watch('someVar', function(newValue, oldValue) {
   if(newValue!==oldValue) {
    console.log(newValue);
    scope.someVar = [Do something with someVar];
   } 
});

Solution 3

This is how dirty-checking works. Every time something on the $scope changes Angular will spin through everything that is attached to the scope and it will keep doing so untill there are no more changes.

If you want to do something like that, you will have to make sure that your $watch function is idempotent. You will have to look at both newValue and oldValue and figure out wether you've already applied the changes to your variable in this $digest loop. How you can do that depends a bit on what kind of changes you're doing to someVar.

Generally speaking, changing a watched variable in a watch-function is unfortunately not a good idea.

Solution 4

you can manage it using a bool variable

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

Solution 5

yes you can cancel it like this

var wathcer = scope.$watch('someVar', function(newValue, oldValue) {
    console.log(newValue);
    scope.someVar = [Do something with someVar];

});
wathcer(); // clear the watch
Share:
65,521
Vivendi
Author by

Vivendi

Updated on June 16, 2020

Comments

  • Vivendi
    Vivendi almost 4 years

    In AngularJS I have a directive that watches a scope variable. When the variable contains certain data then I need to alter that variable a bit. The problem is that when I change the variable that my $watch is triggered again. So I end up in a continuous loop.

    scope.$watch('someVar', function(newValue, oldValue) {
        console.log(newValue);
        scope.someVar = [Do something with someVar];
    });
    

    This keeps triggering $watch again, which makes sense. But I do need a way to change the watched variable. Is there a way to do this?