$apply () and $digest () are two core concepts in angularjs, but sometimes they are confusing. To understand how ANGULARJS works, first you need to understand how $apply () and $digest () work. This article is intended to explain what $apply () and $digest () are, and how to apply them in everyday coding.
1. Explore $apply () and $digest ()
1.1, understanding two-way data binding and $watch ();
ANGULARJS provides a very cool feature called bidirectional data binding (two-way), which greatly simplifies the way our code is written. Data binding means that when any data in a view changes, the change is automatically fed back to the scope data, meaning that the scope model is automatically updated. Similarly, when the scope model changes, the data in view is updated to the most recent value. So how did Angularjs do that? When you write down an expression such as {{Amodel}}, Angularjs sets a watcher on the scope model behind the scenes to update the view when the data changes. The watcher here are the same as the Watcher you will set in Angularjs:
$scope. $watch (' Amodel ', function (NewValue, oldValue) {
//update the DOM with NewValue
});
The second parameter passed into $watch () is a callback function that is invoked when the value of the Amodel changes. When the Amodel changes, this callback function will be called to update view this is not difficult to understand, but there is a very important question! How does Angularjs know when to call this callback function? In other words, how does angularjs know that the Amodel has changed before invoking the corresponding callback function? Does it periodically run a function to check that the data in the scope model has changed? Well, that's where the $digest loop comes in.
In the $digest loop, the watchers is triggered. When a watcher is triggered, Angularjs detects the scope model and how it changes so that the callback function associated with the watcher is invoked. So the next question is, when did the $digest cycle start in a variety of ways?
After invoking the $scope. $digest (), the $digest loop begins. If you change a data in scope in a handler function corresponding to a ng-click instruction, ANGULARJS automatically triggers a round of $digest loops by calling $digest (). When the $digest loop starts, it triggers each watcher. These watchers check whether the current model value in scope differs from the last computed model value. If different, then the corresponding callback function is executed. The result of calling the function is that the content of the expression in the view (such as {{Amodel}}) is updated. In addition to the Ng-click instructions, there are other built-in directives and services that allow you to change models (such as Ng-model, $timeout, etc.) and automatically trigger a $digest loop.
So far so good! However, there is a small problem. In the above example, ANGULARJS does not call $digest () directly, but instead calls $scope. $apply (), which invokes the $rootscope. $digest (). Therefore, a round of $digest loops begins at $rootscope and then accesses all watchers in the children scope.
Note: $scope. $apply () automatically invokes the $rootscope. $digest ().
There are two forms of the $apply () method:
The first type takes a function as an argument, executes the function, and triggers a round of $digest loops.
The second type will not accept any parameters, just triggering a round of $digest loops. We will soon see why the first form is better.
1.2. When do I manually call the $apply () method?
If Angularjs always wrap our code into a function and passes in $apply () to start a round of $digest loops, when do we need to manually invoke the $apply () method? In fact, Angularjs has a very clear requirement that it is only responsible for automatically responding to changes that occur in the context of angularjs (that is, changes to models that occur in the $apply () method). Angularjs's built-in instructions do this, so any model change is reflected in the view. However, if you modify model anywhere outside of the ANGULARJS context, you will need to notify Angularjs by manually calling $apply (). It's like telling Angularjs that you've modified some models, hoping ANGULARJS will help you trigger watchers to make the right response.
For example, if you use SetTimeout () in JavaScript to update a scope model, then ANGULARJS has no way of knowing what you have changed. In this case, calling $apply () is your responsibility, by invoking it to trigger a round of $digest loops. Similarly, if you have a command to set up a DOM event listener and modify some models in the listener, you also need to manually invoke $apply () to ensure that the changes are reflected correctly in the view.
Let's take a look at an example. Join you have a page, once the page has finished loading, you want to display a message after two seconds. Your implementation may be the following:
Html:
<body ng-app= "myApp" >
<div ng-controller= "Messagecontroller" >
delayed message: {{message}}
</div>
</body>
Javascript:
/* What happens without an $apply () * * *
angular.module (' myApp ', []). Controller (' Messagecontroller ', function ($scope {
$scope. getMessage = function () {
settimeout (function () {
$scope. Message = ' fetched after 3 seconds '; C12/>console.log (' message: ' + $scope. message);
}
$scope. GetMessage ();
By running this example, you will see that after two seconds, the console does display the updated model, however, view is not updated. The reason maybe you already know, is that we forgot to call the $apply () method. Therefore, we need to modify the GetMessage () as follows:
/* What happens with $apply *
/angular.module (' myApp ', []). Controller (' Messagecontroller ', function ($scope) {
$scope. getMessage = function () {
settimeout (function () {
$scope. $apply (function () {
//wrapped this within $apply
$scope. Message = ' fetched after 3 seconds ';
Console.log (' message: ' + $scope. message);}
;
};
$scope. GetMessage ();
If you run the example above, you will see that the view is updated after two seconds. The only change is that our code is now wrapped to $scope. $apply (), which automatically triggers the $rootscope. $digest (), allowing watchers to be triggered to update the view.
Note: Incidentally, you should use the $timeout service instead of settimeout (), because the former will help you invoke $apply () so that you do not need to call it manually.
Also, note that in the above code you can also manually invoke $apply () without parameters after modifying model, as follows:
$scope. getMessage = function () {
settimeout (function () {
$scope. Message = ' fetched after two seconds ';
Console.log (' message: ' + $scope. message);
$scope. $apply (); This triggers a $digest
};
The code above uses the second form of $apply (), which is a form without parameters. Remember that you should always use the $apply () method that accepts a function as a parameter. This is because when you pass in a function to $apply (), the function is wrapped in a try...catch block, so the exception is handled by the $exceptionhandler service once an exception occurs.
The use of $apply () is as follows:
• You can usually rely on any instruction provided by angular for use in the view to invoke $apply (). All Ng-[event] directives (such as Ng-click, ng-keypress) call $apply ().
• In addition, you can rely on a series of angular built-in services to invoke $digest (). For example $http service will call $apply () after the XHR request completes and the update return value (Promise) is triggered.
• Whenever we handle events manually, use a Third-party framework (such as jquery, Facebook APIs), or call settimeout (), you can use the $apply () function to let the angular return $digest loop.
Call SetTimeout ():
Use third party frameworks (such as jquery, Facebook APIs):
1.3, how many times will the $digest cycle run?
When a $digest loop runs, watchers is executed to check whether the models in the scope has changed. If a change occurs, the corresponding listener function is executed. This relates to an important issue. What if the listener function itself modifies a scope model? What will Angularjs do with this?
The answer is that the $digest loop does not run only once. At the end of the current loop, it performs a loop again to check if any models has changed. This is the dirty check (Dirty Checking), which is used to handle model changes that may result when the listener function is executed. Therefore, the $digest loop continues to run until model no longer changes, or the number of $digest cycles reaches 10 times. Therefore, try not to modify model in the listener function as much as possible.
Note: The $digest loop will run at least two times, even if the listener function does not change any of the model. As discussed above, it will run more than once to ensure that models does not change.
Conclusion
The most important thing to remember is whether ANGULARJS can detect your changes to model. If it is not detected, then you need to manually invoke $apply ().
If you have any questions please give me a message, small series will promptly reply to everyone. Here also thank you very much for the cloud Habitat Community website support!