It seems that one can achieve the same result using two different approaches:
doSomething();
$scope.$digest();
or
$scope.$apply(function() {
doSomething();
});
So what are the differences and what to use when?
AngularJS $digest
Processes all of the watchers of the current scope and its children. Because a watcher's listener can change the model, the $digest() keeps calling the watchers until no more listeners are firing. This means that it is possible to get into an infinite loop. This function will throw 'Maximum iteration limit exceeded.' if the number of iterations exceeds 10.
Usually, you don't call $digest() directly in controllers or in directives. Instead, you should call $apply() (typically from within a directive), which will force a $digest().
If you want to be notified whenever $digest() is called, you can register a watchExpression function with $watch() with no listener.
In unit tests, you may need to call $digest() to simulate the scope life cycle.
Both will do the same thing. But, using $scope.apply() wrapped as a function is best practice. Why because, when you wrap something in $scope.apply(), you can write catch block for that. So, you can catch any exceptions you may face.
You can check if a $digest is already in progress by checking $scope.$$phase.
if(!$scope.$$phase) {
//use anyone yours: $digest or $apply
}
scope.$digest() will fire watchers on the current scope, and on all of its children, too. scope.$apply will evaluate passed function and run $rootScope.$digest().
See this: $apply vs $digest in directive testing
$scope.$digest() : This is cycle process. So when we call $scope.$digest() it will start a digest cycle and check all the watchers of the scope whatever should changed will be changed, and after that a dirty check will be processed , which will check while the digest cycle was is progress is anything changed , if changed then again the digest cycle will start working.One Should not call $scope.$digest() manually because whenever anything change in the scope it will be called . More details here $digest
$scope.$apply: In $scope.$apply you implicitly tell that only watchers affected by the function will be update or only specific watchers will be checked for the update,it handles exception internally , no manual handling needed . More details $apply
Related
As i was going through the life cycle of scope, I came across $digest should be called by $apply. But I want to know if possible can we enable $digest without $apply. If yes what is disadvantage
when you calls the $scope.$apply() function, it call the $rootScope.$digest(). So as a result of that, digest cycle starts from the rootScope and call all the child scopes.
you can call the digest using $scope.$digest() but this will start the cycle for child scope only. sometimes binding will not properly occur because digest cycle is not starting from the root scope.
you can check this article to get an idea about how the digest cycle works
The $scope.$digest() function iterates through all the watches in the $scope object, and its child $scope objects (if it has any). When $digest() iterates over the watches, it calls the value function for each watch.
The $scope.$apply() function takes a function as parameter which is executed, and after that $scope.$digest() is called internally.
I would appreciate if anyone can provide any real example which can help me to crack the interview.
$digest will be called once you call $apply
here is the source code
function $apply(expr) {
try {
return $eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
}
$apply will just make sure all the changes in the scope values have been absorbed whereas $apply will evaluate all the expressions the it will call the $digest function as you can see in the source code.
$digest Processes all of the watchers of the current scope and its children. Because a watcher's listener can change the model, the $digest() keeps calling the watchers until no more listeners are firing.
If you have any expression in your application that needs to be evaluated before digest cycle then you should use $apply else if you only want to apply changes then you can use $digest.
The difference is that $apply will trigger the digest cycle from the root down, if you call $digest it will trigger from whatever scope it was called from.
I have Confusion in $digest when we need to used ? But $apply I think we need when angular js into any element have outside scope then we use $apply and update it with value.
$digest means same But How can we use so, we used differently.
internally $digest call in this code.
$apply() - Internally calls $digest just the difference is it's $digest cycle starts from the rootscope and visit all child element(their model) and calls $digest on them.
I just want to know how to use $digest. Inside a controller the following code works fine and it updates the DOM after 3 seconds:
setTimeout(function(){
$scope.$apply(function(){
$scope.name = 'Alice';
});
}, 3000);
However by using
setTimeout(function(){
$scope.$digest(function(){
$scope.name = 'Alice';
});
}, 3000);
nothing happens...
I thought that they do the same thing. Am I wrong?
$apply() and $digest() have some similarities and differences. They are similar in that they both check what's changed and update the UI and fire any watchers.
One difference between the two is how they are called. $digest() gets called without any arguments. $apply() takes a function that it will execute before doing any updates.
The other difference is what they affect. $digest() will update the current scope and any child scopes. $apply() will update every scope. So most of the time $digest() will be what you want and more efficient.
The final difference which explains why $apply() takes a function is how they handle exceptions in watchers. $apply() will pass the exceptions to $exceptionHandler (uses try-catch block internally), while $digest() will require you handle the exceptions yourself.
I think you must go through documents $apply
$apply() is used to execute an expression in angular from outside of
the angular framework
Usually, you don't call $digest() directly in controllers or in
directives. Instead, you should call $apply() (typically from within a
directive), which will force a $digest().
Also as suggest by Jorg, use $timeout
In angularjs $scope object is having different functions like $watch(), $digest() and $apply() and we will call these functions as central functions.
The angularjs central functions $watch(), $digest() and $apply are used to bind data to variables in view and observe changes happening in variables.
Generally in angularjs we use $scope object to bind data to variables and use that variables values wherever we required in application. In angularjs whatever the variables we assigned with $scope object will be added to watch list by using $scope.$watch() function.
In angularjs once variables added to watch list $scope.digest() function will iterates through the watch list variables and check if any changes made for that variables or not. In case if any changes found for that watch list variables immediately corresponding event listener function will call and update respective variable values with new value in view of application.
The $scope.$apply() function in angularjs is used whenever we want to integrate any other code with angularjs. Generally the $scope.$apply() function will execute custom code and then it will call $scope.$digest() function forcefully to check all watch list variables and update variable values in view if any changes found for watch list variables.
In most of the time angularjs will use $scope.watch() and $scope.digest() functions to check and update values based on the changes in variable values.
A better understanding of $watch, $apply, and $digest is provided in this article.
Simply,
$watch that is used to detect changes in the UI
$apply would tell the $digest loop what changes should be applied
$digest loop would run and will ask every $watch for changes, the DOMs would change accordingly for what has what has been applied
You should call $apply only.
I want to execute some function on every $digest cycle.
The documentation for $scope reads:
If you want to be notified whenever $digest is called, you can
register a watchExpression function with no listener. (Since
watchExpression can execute multiple times per $digest cycle when a
change is detected, be prepared for multiple calls to your listener.)
So does that mean it can be accomplished this way:
$rootScope.$watch(function () {
// Cron job
});
I'm not sure if every $digest cycle hits the $rootScope, or is it even emitted from $rootScope. I only know there's only 1 $digest loop and it occurs every time a $watch detects changes.
Q: So does that mean it can be accomplished this way?
A: Yes, although some directives/services might choose to only digest their local scope to improve performance.
That said it's recommended to execute as less code as possible in a digest loop.
digest isn't like a cron job, it doesn't run automatically every x seconds.
It runs when you call $scope.$apply() or when an event like ng-click or $http.get occurs.