Reputation: 1904
I am expecting $watch
to fire x
times if you change the variable it is watching x
times. In a little example I put together, I am changing the value of variable $scope.foo
3 times, but the associated $watch
only runs once...
<html>
<head>
<title></title>
<script src="https://code.angularjs.org/1.3.8/angular.js"></script>
</head>
<body ng-app='myApp'>
<div ng-controller='MyCtrl'></div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.$watch('foo', function(oldVal, newVal) {
console.log(oldVal, newVal);
});
$scope.foo = "foo";
$scope.foo = "bar";
$scope.foo = "baz";
});
</script>
</body>
</html>
Would anyone be able to explain what the reason for this is, or a different approach I can take to receive the desired outcome?
I am expecting the following console output:
undefined foo
foo bar
bar baz
but get...
baz baz
myApp.controller('MyCtrl', function($scope, $timeout) {
$scope.$watch('foo', function() {
$scope.bar = 'bar';
});
$scope.foo = "foo";
// now the value of $scope.foo has changed, I was expecting the $watch to have run at this point.
// Apparently is has not because $scope.bar is still undefined. Accessing $scope.bar in a $timeout works, but is there a better way?
console.log($scope.bar)
});
Upvotes: 1
Views: 463
Reputation: 3243
A $watch
will only fire once during each angular $digest cycle! (If watching a property that is - the simplest scenario).
The three changes you are making to foo
are all occurring during the same cycle. And angular will compare the values before the cycle and after the cycle.
For your situation, you need to trigger a new cycle by, for example, changing the values inside a $timeout
.
Edit
For your example you could do something like this
myApp.controller('MyCtrl', function($scope) {
$scope.foo = "foo";
// run on controller init
fooWatch();
// watch for changes
$scope.$watch('foo', fooWatch);
function fooWatch() {
$scope.bar = 'bar';
}
});
Upvotes: 2
Reputation: 880
Because a $digest
cycle isn't run everytime you change a variable in your scope (fortunately).
It is triggered when you use $timeout
though.
What's your use case ?
BTW using $watch
in a controller is often not a good practice and easily avoidable.
Upvotes: 1
Reputation: 866
The change is too quick for angular, with $timeout
it works :
<html>
<head>
<title></title>
<script src="https://code.angularjs.org/1.3.8/angular.js"></script>
</head>
<body ng-app='myApp'>
<div ng-controller='MyCtrl'></div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope, $timeout) {
$scope.$watch('foo', function(oldVal, newVal) {
console.log(oldVal, newVal);
});
$scope.foo = "foo";
$scope.foo = "bar";
$scope.foo = "baz";
$timeout(function(){
$scope.foo = "foo";
},0)
$timeout(function(){
$scope.foo = "bar";
},0)
$timeout(function(){
$scope.foo = "baz";
},0)
});
</script>
</body>
</html>
See How does AngularJS's $watch function work?
Upvotes: 0