简体   繁体   中英

$digest soon after $watch definition triggers “$apply already in progress…” error

I am an angular-noob and I am trying to understand why the following triggers the "$apply is already in progress ..." error.

Here is the code (and its really almost straight from the documentation: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest )

<!DOCTYPE html>
<html>

<head>
    <script src="js/lib/angular.js"></script>
    <script>
    var app = angular.module('app', []);
    app.controller('MainController', ['$scope', function(scope) {
        scope.name = 'misko';
        scope.counter = 0;
        //A
        scope.$watch('name', function(newValue, oldValue) {
            scope.count++;
        });
        //B
        scope.$digest();
    }]);
    </script>
</head>

<body>
    <div ng-app='app' ng-controller="MainController">
    </div>
</body>

</html>

And, here is the fiddle: https://jsfiddle.net/zLny2faq/5/

I get the in-famous "$apply already in progress" error but why is that ?

I would like to know why the digest cycle triggers without even being called ?

In other words, I am merely declaring watch listeners (@comment A) and triggering them by calling $digest() (@comment B) . But it seems like its somehow being called sooner and errors out when I explicitly called $digest(). Why is this so ?

Please advise.

The name variable is set before the watch yes, but all watches get called once on initialization:

Per Angular Docs

After a watcher is registered with the scope, the listener fn is called asynchronously (via $evalAsync) to initialize the watcher. In rare cases, this is undesirable because the listener is called when the result of watchExpression didn't change. To detect this scenario within the listener fn, you can compare the newVal and oldVal. If these two values are identical (===) then the listener was called due to initialization.

^ Can be taken care of via :

$scope.$watch('name', function(newValue, oldValue) {
  if (newValue !== oldValue) {
    // will only run if the value changes, on initial load the newvalue = oldvalue so it won't run this code.
  }
});

If you really need to call $digest, you can use

$timeout(function(){
    scope.$digest();
}, 0);

Fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM