I have a simple custom directive myElement with a templateUrl that print a simple message:
<p>Message: {{message}}</p>
Here's the definition of my directive:
testapp.directive('myElement', function() {
return {
restrict: 'E',
template: '<p>Message: {{message}}</p>',
link: function(scope, elem, attrs) {
scope.message = 'This message is never updated... :(';
setTimeout(function() {
scope.message = "Why this message is never shown?";
}, 1000);
}
};
});
After 1 second, I expect an update of the message to "Why this message is never shown?". Unfortunately, the message is never updated.
Here is the jsFiddle: http://jsfiddle.net/seyz/SNMfc
Could you explain me why?
Due to how Angular dirty checking works, when you execute code outside of angular scope (e.g. using setTimeout, setInterval, or from within some third-party plugin callback) the changes produced by that code invocation won't be 'recognized' immediately by Angular scope.
For such scenarios you need to wrap your code inside the scope.$apply() method.
In this particular case you may simply use $timeout function to replace your setTimeout(fn, 1000)call with $timeout(fn, 1000)and your code will be wrapped with scope.$apply() call (Plunker).
You will need to use scope.$apply();
setTimeout(function() {
scope.message = "Why this message is never shown?";
scope.$apply();
}, 1000);
From the documentation:
$apply() is used to execute an expression in angular from outside of the angular framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).