Understanding $apply () and $digest () in angular

Source: Internet
Author: User
<span id="Label3"></p>A recent manual call with Angularjs $apply always encounters an error: $degist already in Progress. After a few online search found, in fact, because I use the $apply is not clear generated.       So read a few blog, Enlightened. Let's talk about why you use $apply, the official document Explains: it is only responsible for<span lang="en-US"><span lang="en-US">AngularJS <span lang="zh-CN">Changes in the context are automatically responded to. What do you mean, in Layman's terms, If you modify the model outside of the Angularjs context, then you have to manually pass $apply to let angular know that the view must be Refreshed. This problem is more prominent on settimeout (), when the model can play the updated value from the console, but the angular on the view is not changed, because no apply is Used. There are two ways to invoke apply, one of which is $scope. $apply (function () {}) Another type of direct $scope without Parameters. $apply (); now that $apply has been said, say $degist. We all know that a very important feature of angular is two-way binding, and when the model changes, the view changes, so when does Angularjs know how to change the view? This leads to the $degist, which is triggered in the degist, and then Ng examines the scope model, and if it changes, the callback function associated to the watcher is Called. The $degist loop does not run only once, and every time the loop ends, the model that the listener function is executed is checked for changes, which is the dirty check that is often heard, $degist the loop continues to run until the model no longer changes. So try to modify the model as little as possible in the Listener. </span></span></span><p><p></p></p><p><p><span style="font-size: 16px; color: #ff0000;"><strong><span lang="en-US">Original Blog Content:</span></strong></span></p></p><p><p></p></p><p><p><span lang="en-US">$apply () <span lang="zh-CN">and <span lang="en-US">$digest () <span lang="zh-CN"> <span lang="en-US"> <span lang="zh-CN">are two core concepts in AngularJS, but sometimes they are confusing. To understand <span lang="en-US">how AngularJS <span lang="zh-CN">works, you first need to understand <span lang="en-US">how $apply () <span lang="zh-CN">and <span lang="en-US">$digest () <span lang="zh-CN">Work. This article <span lang="en-US">is intended to explain what $apply () <span lang="zh-CN">and <span lang="en-US">$digest () <span lang="zh-CN">are, and how they are applied in everyday coding. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><strong><span style="font-size: 16px; color: #3366ff;" lang="zh-CN">Explore <span lang="en-US">$apply () <span lang="zh-CN">and <span lang="en-US">$digest ()</span> </span> </span></span></strong></p></p><p><span lang="en-US">AngularJS<span lang="zh-CN">Provides a very cool feature called two-way data binding<span lang="en-US"><span lang="en-us" (two-way data binding) <span , this feature greatly simplifies the way our code is written. binding means that when any data in>view<span lang="en-us" is changed, the change automatically fed back to <span>scope <span lang="en-us" data, that means <span>scope<span lang="en-us" and the model is automatically updated. similarly, when <span>scope<span lang="zh-cn"> model changes, <span lang="en-us">view<span lang="zh-cn"> The data in is also updated to the most recent Value. So <span lang="en-us">angularjs<span lang="en-us" how to do this? when you write down an expression such as <span>{{aModel}}<span lang="en-us" , <span>angularjs<span lang="zh-cn"> Behind the scenes you set up a ZH-CN <span "en-us" lang>watcher<span "lang=" on the <span lang= " en-us">scope<span lang="zh-cn"> It is used to update <span lang="en-us">view<span lang="en-us" when data changes. here the <span>watcher<span lang="zh-cn" and you set the < span> in <span lang="en-us">angularjs<span lang="zh-cn"> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></span><span style="line-height: 1.5;"><span style="line-height: 1.5;">of the</span></span><span style="line-height: 1.5;" lang="en-US"><span style="line-height: 1.5;" lang="en-US">Watcher <span lang="zh-CN">is the same:</span> </span></span></p><pre><pre><span style="color: #0000ff;">function</span> <span style="color: #000000;">(newvalue, oldValue) { </span><span style="color: #008000;">//</span><span style="color: #008000;">Update the DOM with NewValue</span>});</pre></pre><p><p><span lang="zh-CN"><span lang="en-US">The second parameter passed into the $watch () <span lang="zh-CN">is a callback function that is <span lang="en-US"> <span lang="zh-CN">called when the value of AModel Changes. <span lang="en-US"> <span lang="zh-CN">This callback function is not difficult to understand when the AModel is changed, <span lang="en-US"> <span lang="zh-CN">but there is a very important problem! <span lang="en-US">How does AngularJS <span lang="zh-CN">know when to invoke this callback function? In other words, how does AngularJS know that the AModel has changed<span lang="en-US"> <span lang="zh-CN"> <span lang="en-US"> <span lang="zh-CN">before invoking the corresponding callback function? Does it periodically run a function to check <span lang="en-US"> <span lang="zh-CN">if the data in the scope model has changed? well, That's where the <span lang="en-US">$digest <span lang="zh-CN">Loop comes in. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="zh-CN">In the <span lang="en-US">$digest <span lang="zh-CN">loop, The<span lang="en-US">watchers <span lang="zh-CN">is Triggered. When a <span lang="en-US">watcher <span lang="zh-CN">is triggered,<span lang="en-US">AngularJS <span lang="zh-CN">detects the <span lang="en-US">scope <span lang="zh-CN">model and how it changes so that the callback function associated to the watcher is <span lang="en-US"> <span lang="zh-CN">Called. So the next question is, <span lang="en-US"> <span lang="zh-CN">when does the $digest cycle start in various ways? </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><span lang="zh-CN">After calling the<span lang="en-US">$scope. $digest ()<span lang="zh-CN">After<span lang="en-US">$digest<span lang="zh-CN">The Cycle Begins. Suppose You're in a<span lang="en-US">Ng-click<span lang="zh-CN">directive corresponds to the<span lang="en-US">Handler<span lang="zh-CN">function changes the<span lang="en-US">Scope<span lang="zh-CN">One of the data in this<span lang="en-US">AngularJS<span lang="zh-CN">is automatically passed through the call to the<span lang="en-US">$digest ()<span lang="zh-CN">To trigger a round<span lang="en-US">$digest<span lang="zh-CN">Cycle. When<span lang="en-US">$digest<span lang="zh-CN">Once the loop is started, it triggers each<span lang="en-US"><span lang="en-us">watcher<span lang="en-us" . these <span>watchers<span lang="en-us" will check the current in <span>scope<span lang="The" <span value of "en-us">model<span lang="en-us" is different from the last computed <span>model<span lang="en-us" . if it is different, then the corresponding callback function will be executed. the result of calling this <span>view<span lang="en-us" to the expression content <span> (<span lang="en-us" ): such as <span>{{aModel}) <span lang="en-us" will be updated. in addition to <span>ng-click<span lang="zh-cn"> directives, There are other <span lang="en-us">built-in<span lang="zh-cn"> Instructions and services to let you change <span lang="en-us">models (<span lang="en-us" ) such as <span>ng-model<span lang="zh-cn">,<span lang="en-us"> $timeout <span lang="zh-cn"> et <span lang="en-us">) <span lang="en-us" and automatically triggered once <span>$ Digest<span lang="zh-cn"> loop. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><p><p><span lang="zh-CN">So far it's good! however, There is a small problem. In the example above,<span lang="en-US">AngularJS <span lang="zh-CN">does not call <span lang="en-US">$digest () directly<span lang="zh-CN">, but instead calls the <span lang="en-US">$scope. $apply ()<span lang="zh-CN">, which calls the <span lang="en-US">$rootScope. $digest ()<span lang="zh-CN">. therefore, a round of <span lang="en-US">$digest <span lang="zh-CN">cycle <span lang="en-US">starts in the $rootScope <span lang="zh-CN">and then accesses all the <span lang="en-US">watchers in the children scope <span lang="zh-CN"> <span lang="en-US"><span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="zh-CN">now, Suppose you <span lang="en-US">associate the Ng-click <span lang="zh-CN">directive to a <span lang="en-US">button and <span lang="zh-CN">pass in a <span lang="en-US">function <span lang="zh-CN">name to <span lang="en-US">Ng-click <span lang="zh-CN">. When the <span lang="en-US">button <span lang="zh-CN">is clicked,<span lang="en-US">AngularJS <span lang="zh-CN">wraps the <span lang="en-US">function <span lang="zh-CN">into a <span lang="en-US">wrapping function and <span lang="zh-CN">then passes in to <span lang="en-US">the Scope. $apply ()<span lang="zh-CN">. As a result, your <span lang="en-US">function <span lang="zh-CN">will be executed normally, modify the <span lang="en-US">models ( <span lang="zh-CN">if necessary <span lang="en-US">)<span lang="zh-CN">, and a round <span lang="en-US">$digest <span lang="zh-CN">Loop will be triggered to ensure that the <span lang="en-US">view <span lang="zh-CN">will also be updated. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="en-US">Note: $scope. $apply () <span lang="zh-CN">automatically calls <span lang="en-US">$rootScope. $digest ()<span lang="zh-CN">. <span lang="en-US"> <span lang="zh-CN">There are two forms of the $apply () method. The first one takes a <span lang="en-US">function <span lang="zh-CN">as a parameter, executes the <span lang="en-US">function <span lang="zh-CN">and triggers a round <span lang="en-US">$digest <span lang="zh-CN">loop. The second one will not accept any arguments, just trigger a round of <span lang="en-US">$digest <span lang="zh-CN">loops. we'll See now why the first form is Better. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span style="color: #3366ff;"><strong><span style="font-size: 16px;" lang="zh-CN">When do I manually invoke the <span lang="en-US">$apply () <span lang="zh-CN">method? </span></span></span></strong></span></p></p><p><p></p></p><p><span lang="zh-CN">If<span lang="en-US">AngularJS<span lang="zh-CN">Always put our code<span lang="en-US">Wrap<span lang="zh-CN">to a<span lang="en-US">function<span lang="zh-CN">In and incoming<span lang="en-US">$apply ()<span lang="zh-CN">To start a round<span lang="en-US">$digest<span lang="zh-CN">loop, then when do we need to manually call<span lang="en-US">$apply ()<span lang="zh-CN">method? As a matter of fact<span lang="en-US">AngularJS<span lang="zh-CN">There is a very clear requirement that it is only responsible for the<span lang="en-US">AngularJS<span lang="zh-CN">Changes in the context are automatically responded to<span lang="en-US">(<span lang="zh-CN">That is, in<span lang="en-US"><span lang="en-us"> $apply () <span lang="zh-cn"> changes to <span lang="en-us">models<span lang="en-us" <span ) .>angularjs<span lang="zh-cn"> <span lang="en-us">built-in<span lang="zh-cn"> directive is doing so, so any of the The change of span lang= "en-us" >model<span lang="en-us" will be reflected in <span>view<span lang . however, if you modify zh-cn <span "en-us">model<span "lang=" anywhere outside the context of <span lang= " en-us">angularjs<span lang , then you need to notify zh-cn <span "en-us">angularjs<span "lang=" by manually calling <span lang= " en-us"> $apply () <span lang="en-us" . this is like telling <span>angularjs<span lang="en" , you have modified some <span>models<span lang="en-us" and hope that span>angularjs<span lang="en-us" to help you trigger <span>watchers<span lang="zh-cn" to make the right response. < span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><p><p></p></p><p><p><span lang="zh-CN">For example, If you use <span lang="en-US"> <span lang="zh-CN"> <span lang="en-US">setTimeout () in JavaScript <span lang="zh-CN">to update a <span lang="en-US">scope model<span lang="zh-CN">, there is <span lang="en-US">no way for AngularJS to <span lang="zh-CN">know what you have Changed. In this case, calling <span lang="en-US">$apply () <span lang="zh-CN">is your responsibility, by invoking it to trigger a round of <span lang="en-US">$digest <span lang="zh-CN">loops. similarly, If you have an instruction to set up a <span lang="en-US">DOM <span lang="zh-CN">event <span lang="en-US">listener <span lang="zh-CN">and <span lang="en-US"> <span lang="zh-CN">modify some models in the listener <span lang="en-US"><span lang="zh-CN">, you also need to manually call <span lang="en-US">$apply () <span lang="zh-CN">to ensure that changes are correctly reflected in the <span lang="en-US">view <span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></p></p><p><p></p></p><p><p>Let's take a look at an example. Join you have a page, once the page has been loaded, you want to display a message after two SECONDS. Your implementation might look something like this:</p></p><p><p></p></p><p><p>Html:</p></p><pre><pre><span style="color: #0000ff;"><</span><span style="color: #800000;"></span><span style="color: #ff0000;">ng-app</span><span style="color: #0000ff;">= "myApp"</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;"></span><span style="color: #ff0000;">Ng-controller </span> <span style="color: #0000ff;">= "messagecontroller"</span><span style="color: #0000ff;">></span><span style="color: #000000;"> Delayed message: {{Message}} </span><span style="color: #0000ff;"></ </span> <span style="color: #800000;">div</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"></</span><span style="color: #800000;">body</span><span style="color: #0000ff;">></span></pre></pre><p><p>Javascript:</p></p><pre><pre> <span style="color: #008000;">/* </span> <span style="color: #008000;"> What happens without an $apply () </span> Span style= "color: #008000;" >*/ <span style="color: #000000;"> angular.module (</span> ' myApp ', []). controller (' messagecontroller ', <span style="color: #0000ff;">function </span> <span style="color: #000000;"> ($scope) {$scope. getMessage </span> = <span style="color: #0000ff;">function </span> <span style="color: #000000;"> () {setTimeout (</span> <span style="color: #0000ff;">function </span> <span style="color: #000000;"> () {$scope. message </span> = ' fetched after 3 seconds ' <span style="color: #000000;" message: ' +<span> $scope. message); }, </span> 2000<span style="color: #000000;">); } $scope. getMessage (); });</span></pre></pre><p><p><span lang="zh-CN">By running this example, you will see that after two seconds, the console does show the updated <span lang="en-US">model<span lang="zh-CN">, however, the<span lang="en-US">view <span lang="zh-CN">is not Updated. Maybe you already know that we forgot to call the <span lang="en-US">$apply () <span lang="zh-CN">method. therefore, We need to modify the <span lang="en-US">getMessage ()<span lang="zh-CN">as follows:</span> </span> </span> </span> </span> </span> </span> </span></span></p></p><pre><span style="color: #008000;"><span style="color: #008000;">/*</span></span><span style="color: #008000;">what <span style="color: #008000;">happens with $apply</span></span><span style="color: #008000;"><span style="color: #008000;">*/</span></span><span style="color: #000000;"><span style="color: #000000;">Angular.module (</span></span>' MYAPP ', []). controller (' Messagecontroller ',<span style="color: #0000ff;"><span style="color: #0000ff;">function</span></span><span style="color: #000000;"><span style="color: #000000;">($scope) {$scope. getMessage</span></span>=<span style="color: #0000ff;"><span style="color: #0000ff;">function</span></span><span style="color: #000000;"><span style="color: #000000;">() {setTimeout (</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">function</span></span><span style="color: #000000;"><span style="color: #000000;">() {$scope. $apply (</span></span><span style="color: #0000ff;"><span style="color: #0000ff;">function</span></span><span style="color: #000000;"><span style="color: #000000;">() { </span></span><span style="color: #008000;"><span style="color: #008000;">//</span></span><span style="color: #008000;"><span style="color: #008000;">wrapped this within $apply</span></span>$scope. message = ' fetched after 3 seconds '<span style="color: #000000;"><span style="color: #000000;">; Console.log (</span></span>' Message: ' +<span style="color: #000000;"><span style="color: #000000;">$scope. message); }); }, </span></span>2000<span style="color: #000000;"><span style="color: #000000;">); } $scope. getMessage (); });</span></span></pre><p><p><span lang="zh-CN">If you run the example above, you will see that the <span lang="en-US">view is <span lang="zh-CN">updated after two seconds. The only change is that our code is now <span lang="en-US">wrapped <span lang="zh-CN">to <span lang="en-US">$scope. $apply () <span lang="zh-CN">, it automatically triggers <span lang="en-US">$rootScope. $digest ()<span lang="zh-CN">, allowing <span lang="en-US">watchers <span lang="zh-CN">is triggered to update the <span lang="en-US">view<span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="en-US">Note: by <span lang="zh-CN">The way, you should use the <span lang="en-US">$timeout service <span lang="zh-CN">instead <span lang="en-US">of SetTimeout ()<span lang="zh-CN">, because the former will help you call <span lang="en-US">$apply ()<span lang="zh-CN">, So you don't need to call it manually. </span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="zh-CN">also, Note that in the above code you can <span lang="en-US"> <span lang="zh-CN">manually invoke the $apply () without parameters after modifying the model <span lang="en-US"><span lang="zh-CN">, as Follows:</span> </span> </span> </span></span></p></p><pre><pre><span style="color: #0000ff;">function</span> <span style="color: #000000;">() { setTimeout</span>(<span style="color: #0000ff;"></span><span style="color: #000000;">) </span>{= ' fetched after-seconds '<span style="color: #000000;">; Console.log (</span>' message: ' +<span style="color: #000000;"> $scope. message); </span> <span style="color: #008000;">//</span> this <span style="color: #008000;">triggers a $digest</span> }, a<span style="color: #000000;">);};</span></pre></pre><p><p><span lang="zh-CN">The code above uses the <span lang="en-US">second form of the $apply () <span lang="zh-CN">, which is the form without Parameters. Remember that you should always use a <span lang="en-US"> <span lang="zh-CN"> <span lang="en-US">$apply () method that accepts a function as a parameter <span lang="zh-CN">. This is because when you pass a <span lang="en-US">function <span lang="zh-CN">into <span lang="en-US">the $apply ( <span lang="zh-CN">), The function is <span lang="en-US">wrapped in <span lang="zh-CN">a <span lang="en-US">try<span lang="en-US">... <span lang="en-US">catch <span lang="zh-CN">block, so that if an exception occurs, the exception is <span lang="en-US">handled $exceptionHandler service <span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span style="font-size: 16px;"><strong><span style="color: #3366ff;" lang="en-US"><span lang="zh-CN">How many times will the $digest loop run? </span></span></strong></span></p></p><p><p></p></p><p><p><span lang="zh-CN">When a <span lang="en-US">$digest <span lang="zh-CN">loop runs,<span lang="en-US">watchers is <span lang="zh-CN">executed to check <span lang="en-US"> <span lang="zh-CN">if the models in the <span lang="en-US">scope <span lang="zh-CN">has Changed. If there is a change, the corresponding <span lang="en-US">listener <span lang="zh-CN">function will be executed. This relates to an important issue. What if the <span lang="en-US">listener <span lang="zh-CN">function itself modifies a <span lang="en-US">scope model <span lang="zh-CN">? <span lang="en-US"> <span lang="zh-CN">What will AngularJS do with the situation? </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span lang="zh-CN">The answer is that the <span lang="en-US">$digest <span lang="zh-CN">Loop does not run only Once. At the end of the current cycle, it will perform a loop again to check if any <span lang="en-US">models have changed <span lang="zh-CN">. This is the dirty check <span lang="en-US">(Dirty Checking)<span lang="zh-CN">, which is used to handle the <span lang="en-US"> <span lang="zh-CN">model changes that can be caused when the listener function is executed <span lang="en-US"> <span lang="zh-CN">. As a result, the<span lang="en-US">$digest <span lang="zh-CN">cycle runs <span lang="en-US">until <span lang="zh-CN">the model no longer changes, or <span lang="en-US"> <span lang="zh-CN">the number of $digest loops reaches <span lang="en-US">ten <span lang="zh-CN">Times. therefore, try not to modify the model in the listener function as much as possible <span lang="en-US"> <span lang="zh-CN"> <span lang="en-US"><span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></p></p><p><p></p></p><p><p><span lang="en-US">Note: the $digest <span lang="zh-CN">Loop will run at least two times, even if the <span lang="en-US">listener <span lang="zh-CN">function does not change any <span lang="en-US">model<span lang="zh-CN">. As discussed above, it will run more than once to ensure that the <span lang="en-US">models <span lang="zh-CN">is Unchanged. </span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p><span style="color: #3366ff;">Conclusion</span></p></p><p><p></p></p><p><p><span lang="zh-CN">I hope this article explains the <span lang="en-US">$apply <span lang="zh-CN">and $digest clearly <span lang="en-US"><span lang="zh-CN">. The most important thing to remember is <span lang="en-US"> <span lang="zh-CN">whether AngularJS can detect your modifications to <span lang="en-US"> <span lang="zh-CN">the Model. If it cannot be detected, then you need to call <span lang="en-US">$apply () manually<span lang="zh-CN">. </span></span></span></span></span></span></span></span></span></span></span></p></p><p><p><span lang="zh-CN"><span lang="en-US"><span lang="zh-CN"><span lang="en-US"><span lang="zh-CN"><span lang="en-US"><span lang="zh-CN"><span lang="en-US"><span lang="zh-CN"><span lang="en-US"><span lang="zh-CN">Original Address:<span style="text-decoration: underline;"><span style="color: #ff0000;"><span style="color: #ff0000; text-decoration: underline;">http://www.sitepoint.com/understanding-angulars-apply-digest/</span></span></span></span></span></span></span></span></span></span></span></span></span></span></p></p><p><p></p></p><p><p>Understanding $apply () and $digest () in angular</p></p></span>

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.