Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top