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.
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.
Say we have the following simple form:
<form ngSubmit="doSomething()">
<input type="submit" value="Submit" />
<form>
And in the controller:
var ctrl = this;
ctrl.doSomething = function () {
// Anything can happen here
}
I know the digest cycle is triggered by ngSubmit, but how does Angular know when to run the digest cycle? Is it run after doSomething() is complete, and if so how does angular know that doSomething() has indeed completed because I haven't seen any examples of ngSubmit functions using a return statement? e.g.
ctrl.doSomething = function () {
// Anything can happen here
// Add return statement so that angular knows callback is complete perhaps?
return;
}
The reason I ask is because within my own doSomething() function I'm updating a scope value e.g. ctrl.myValue++. The updated value is being updated/reflected in the model fine but I don't understand how, or rather when, angular is able to ascertain that doSomething() has finished and it's now time to safely start the digest cycle.
I know the digest cycle is triggered by ngSubmit
Yes, ngSubmit directive like ngClick triggers digest cycle
I haven't seen any examples of ngSubmit functions using a return statement?
Please read more about Scope Life Cycle
"... assignment such as $scope.username="angular" will not immediately cause a $watch to be notified, instead the $watch notification is delayed until the $digest phase. This delay is desirable, since it coalesces multiple model updates into one $watch notification as well as guarantees that during the $watch notification no other $watches are running. If a $watch changes the value of the model, it will force additional $digest cycle."
So when you call ctrl.myValue++, the model changes and it fires digest cycle
Add return statement so that angular knows callback is complete perhaps?
No, I don't think so and this approach has not mentioned in Angular DOCs
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
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 have this code inside an angular directive, and I'm finding the $watch behavior a bit confusing. The updateSelect is called in an "ng-click":
scope.updateSelect = function (type) {
scope.selectionCtrl.activeList = scope.seedLists[type];
scope.selectionCtrl.activeListKey = type;
scope.selectionCtrl.activeSelection = scope.selection[type];
scope.selectionCtrl.staged = [];
scope.selectionCtrl.stageRemove = [];
if (type !== scope.activeTab) {
scope.activeTab = type;
}
console.log("update");
};
scope.$watch('selectionCtrl.activeList', function(newValue, oldValue) {
console.log("watch");
}, true);
When I click on the button (triggering updateSelect), and watch the console, I see "update" and then "watch". The first thing that happens inside the function is selectionCtrl.activeList is set, so I would expect to see "watch" and then "update".
Shouldn't watch trigger as soon as the array has changed?
The function has to finish first as javascript is single threaded.
Because the function was called via the ng-click directive, angular will run a digest cycle. Part of that digest cycle is to run through the watch list and resolve all the changes that may have occurred since the cycle last ran.
In the example you give, selectionCtrl.activeList is changed in updateSelect which subsequently results in the watch callback being called.
When does Angular execute watch callback?
It's related to $digest and $apply, and certainly it does not execute within your raw javascript code.
To make watch execute forcefully, you can run $scope.apply() manually, but may cause more problem and not necessary if it is within a angularjs function, i.e. $timeout, $interval, etc, because it will be called automatically after the function.
For more info., lookup;
How do I use $scope.$watch and $scope.$apply in AngularJS?
https://groups.google.com/forum/#!topic/angular/HnJZTEXRztk
https://docs.angularjs.org/api/ng/type/$rootScope.Scope :
The watchExpression is called on every call to $digest() and should return the value that will be watched. (Since $digest() reruns when it detects changes the watchExpression can execute multiple times per $digest() and should be idempotent.)
If you try i.e.:
scope.selectionCtrl.activeList = scope.seedLists[type];
scope.$digest();
you'll get Error: [$rootScope:inprog] $apply already in progress.