When is it safe to use $scope.$apply()?
The $apply, should be used when the code is not executed in a angular digest loop. In normal circumstances we will not need to use it, but we might have to use it if we have a code that is called from a jQuery event handler or from methods like setTimeout()
. Even if you have a function that is called from another angular function like a watch
or angular event handlers you need not use $apply() as those scripts are executed in the digest cycle.
One safe way is to check the $scope.$$phase
param before calling $scope.$apply() like
if($scope.$$phase){
$scope.$apply();
}
In your case but you can use $timeout as suggested in the another answer
- What is $$phase in AngularJS?
- Why is using if(!$scope.$$phase) $scope.$apply() an anti-pattern?
Edit It was not clear the OP was trying to mock a backend call. Even so, using the $timeout
service is a great way to avoid the need of calling $scope.$apply
manually and is a more generally applicable solution than using a Promise (in cases where you're i.e. not calling $http
it doesn't always make sense to force your changes into the next cycle by wrapping them with a Promise).
Update your code to use the $timeout service and it should work without having to call
$apply
.
$timeout
is a wrapper around the native setTimeout
with an important difference: $timeout
will delay the execution at least until the next $digest
cycle runs.
So passing in no delay will still delay the execution up until the next cycle. Passing in 2000 will delay the execution up to the next cycle after 2000ms.
Hence, this is an easy trick to make sure your changes are picked up by Angular without ever having to call $apply
manually (which is considered unsafe in any case)
function MyCtrl($scope, $timeout) {
$scope.items = [{name : "abc"},{name : "xyz"},{name : "cde"}];
$scope.change = function(){
test(function(testItem){
$scope.items = testItem;
//$scope.$apply();
})
}
function test(callback){
var testItem = [
{name : "mno"},
{name : "pqr"},
{name : "ste"}
];
$timeout(function(){callback(testItem)},2000);
}
}
If you want to immidate an API-Rest-Call, use the returned promise
in your Controller
instead setting the scope inside the Rest-Call.
$http.get('uri')
.success(function(data) {
$scope.items = data
});
Avoid using $apply()
. From the Angular GitHub Repo:
$scope.$apply()
should occur as close to the async event binding as possible.Do NOT randomly sprinkle it throughout your code. If you are doing if
(!$scope.$$phase) $scope.$apply()
it's because you are not high enough in the call stack.
To your question:
- If you find yourself in a situation where you need $apply(), rethink your structure.
- Just for safety reason: Never use
$apply()
You need to use $apply every time you use something that is not "angular way", like Anzeo told about $timeout.
For example if you use jQuery's http instead of angular's $http, you will have to add $scope.$apply.