Search code examples
angularjsdigest

When does the digest get triggered in AngularJS


All:

I got a question about how angularjs data digest monitor the changing of scope data, for example:

 <button ng-click="changename()">{{name}}</button>

And the data change function is like:

            $scope.name = "Change Name";
            $scope.changename = function(){
                $scope.name = "name1";
                $scope.name = "name2";
            }

            $scope.$watch("name", function(newname, oldname){
                if(newname!=oldname){
                    console.log("new: "+newname, "old: "+oldname);
                }
            });

This changename function change scope.name twice in a row, but the watcher can only catch the change from "Change Name" to "name2" ( the console only print "new: name2 old: Change Name")

Could anyone confirm my guess that the digest cycle only start after a function block finish executing?

Thanks


Solution

  • I want to correct the answer from rbaghbanli which is misleading.

    Indeed, because JavaScript is single threaded, what happen when you click on that button is:

    The variable `$scope.name` is set to "name1";
    The variable `$scope.name` is set to "name2";
    > end of execution stack
    
    Angular runs a $digest cycle
    The $watchers are executed
    since a watcher value has changed, angular runs another $digest cycle
    The $watchers are executed
    The watcher have the same value, end of $digest cycle
    > end of execution stack
    

    So basically no watcher nor anything will happen when you are within the same function, until the end of every line of this function.

    The reason why Angular runs a digest cycle after your changename call is because it is within a ng-click directive, and as with all Angular built-in directive, the code is actually wrapped inside a $scope.$apply call. You could read the ng-click as the following code (even if technically it is not exactly like this):

    element.on('click', function() {
      $scope.changename();
      $rootScope.$digest();
    });
    

    Note: I wanted to simplify the generic idea, but to be technically true, Angular executes its $digest cycle right after your code (as you can see in my pseudo ng-click), within the same execution stack. Which means any setTimeout or other asynchronous call will happen after the digest cycle and after the DOM has been updated with the latest changes, which can be useful sometimes.