Reputation: 4869
I'm having some difficulty watching a scope variable from within a directive.
I have a controller with a scope variable called val:
$scope.val = { name: "hello" };
I have a directive which uses this value. So in the view for this controller I have something along the lines of:
<custom-component custom-attribute="val"></custom-component>
I've built a directive which has a scope
var myDir = function() {
return {
restrict: 'E',
scope: {
customAttribute: '=customAttribute'
},
link: function(scope, elem, attr) {
scope.$watch('customAttribute', function(val){ console.log(val); }
},
replace: true,
template:'<div class="hello"></div>'
};
}
The watch function fires of fine when I first run the app. Now I put a timeout in my controller and do something like:
setTimeout(function(){
console.log("Changed chart type name");
$scope.customAttribute.name="baz";
},5000);
This does not cause the watch function to trigger! I'm not sure what the issue is. I've also tried putting the timeout within the directives link function in case there were some object copying issues (below scope.$watch):
link: function(scope, elem, attr) {
scope.$watch('customAttribute', function(val){ console.log(val); }
setTimeout(function(){
console.log("Changed chart type name");
scope.customAttribute.name="baz";
},5000);
},
This still doesn't work!
EDIT:
So I've found that if in my controller I call $scope.$digest() after updating the variable everything works. Why do I need to call this function manually?
Upvotes: 1
Views: 1816
Reputation: 19738
Instead of setTimeout
, use $timeout
, which is the AngularJS equivalent. It uses $scope.$apply internally. With setTimeout
, things happen outside the "Angular World", and your application is not aware of them.
Don't forget to inject $timeout
into your controller:
.controller('MyCtrl', ['$timeout', function($timeout) {
...
}]);
Upvotes: 3
Reputation: 19037
Since you are using setTimeout which is called outside of angular context so you have to call scope.$apply , there are two ways to solve your problem
1) Use scope.$apply()
link: function(scope, elem, attr) {
scope.$watch('customAttribute', function(val){ console.log(val); }
setTimeout(function(){
console.log("Changed chart type name");
scope.customAttribute.name="baz";
scope.$apply();
},5000);
},
2) Wrap the function in angular $timeout
link: function(scope, elem, attr) {
scope.$watch('customAttribute', function(val){ console.log(val); }
$timeout(function(){
console.log("Changed chart type name");
scope.customAttribute.name="baz";
},5000);
},
Upvotes: 3