$apply in setTimeout

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.

Answers


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.


Need Your Help

How do I register a font only for an English version?

cocoa macos fonts locale

My client has given me a custom TTF font only for English. So my intention is to load that TTF only for English and for other languages it should fallback to the available System font.

How to build Generic code for insert data into database using stored procedure?

sql-server c#-4.0 stored-procedures ado.net

So far I used to with ADO.NET code to insert the data into sql database/table using the stored procedure by mapping the stored procedure parameters with values. But is there any generic code which ...