I konw that $apply
used to connect the Javascript context and the AngularJS context.
A simple example is below:
template:
<div>{{someVal}}</div>
javascript in controller:
setTimeout(function() {
scope.$apply(function(){scope.someVal = 123});
}, 1000);
We need use $apply
in above situation.
First Qustion:
If I modify javascript above to:
setTimeout(function() {
scope.someVal = 123;
}, 1000);
scope.$watch('someVal', function(val) {
console.info(someVal);
});
No console about someVal modified to 123... Why? Can't we watch expression modified in timeout callback?
Second Question:
If we use ngSwitch directive like below:
<div ng-switch on="sub">
<div ng-switch-when="a">
//state a
</div>
<div ng-switch-when="b">
//state b
</div>
</div>
When I modify the sub
in controller:
scope.sub = 'a';
setTimeout(function() {
scope.sub = 'b';
}, 1000);
No need to use $apply
!!!! Why?
I found that ngSwitch directive use $watch
to monitor on
attribute value. Why ngSwitch can watch scope attribute modified in timeout callback?????
Pls tell me the reason about the 2 qustions above.
From AngularJs 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). Because we are calling into the angular framework we need to perform proper scope life cycle of exception handling, executing watches.
window.setTimeout is a JavaScript function, so whatever you use setTimeout
you must use $apply() to update the model.
Your second example wouldn't work without $apply()
, I've made a demo to clarify the $watch
and $apply
issue. Please check it.
You can use $timeout that is a wrapper for window.setTimeout and also this way you wont need to use $apply on the callback:
$timeout(function() {
scope.someVal = 123; }, 1000);
When you run code that is outside Angular, you'll need a way to let the Angular and the watchers of that value, to know that it has changed. Thats what $apply is for, it will allow watch listeners to fire
About you second question, of why the scope is updating without a $apply, you should be firing indirectly somehow a $apply/$digest. To give you a more specific answer, a Plunker will be necessary to check what else in going on on your code.
Use the Angularjs $timeout service instead of setTimeout and you will not require $apply. Same thing is if you are using a jquery http call, use the angular http service to avoid using $apply.