Difference between $apply() and $evalAsync()

Asked

Viewed 377 times

1

In an application where I have loaded several indicators from a dashboard I am using the $apply() function to update the data of these indicators but in the console it presents the error "Error: [$rootScope:inprog]", I changed the function to $evalAsync() and the error has not occurred anymore and application is working normally. (I did it in trial and error).

What is the difference in functions ?

  • Well, I know that the $digest do Angularjs does not accept that two run at the same time. When you put async, It’s like you’re "scheduling" the evaluation for the cystic pOxymo

  • Right, so since I have multiple load indicators at the same time the $apply(), does not accept loading all the same time already the $evalAsync() "schedule" to load one at a time ?

  • Yes. The $apply even should be used when you are sure that in the place where you call $apply, is not covered by some cycle recognized by Angularjs. For example, an event that was used with jQuery, or the onscroll window.

  • Thank you very much, problem already solved.

1 answer

1


You seem to be having trouble with the Angularjs data update cycle.

Angularjs configures most events to update/sync values between views and controllers. An example of this is input (talk of the event oninput) when you use the ng-model.

Naturally, we could say that Angularjs calls a method of synchronizing the values each time these events are triggered.

In this case, I believe that these methods are the $apply or $digest².

Specifically speaking of $digest, this as purpose of calling all the $watchers¹ (either manually created or automated, or in the case of ng-model or ng-if) every action taken by the user.

These guys are responsible for the magic of Angularjs, behind the synchronization of values between View and Controller.

The problem usually occurs when you try to call the method $digest or $apply in Angularjs, without the call of the same is not outside this Angular cycle. Because the Angular automatically is already programmed to call them. Trying to do it manually causes an error:

angular.module('app', [])

.controller('AppController', function ($scope) {

    $scope.name = 'Wallace';
    
    $scope.$digest();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>

<div ng-app="app">
   <div ng-controller="AppController"> Hello, {{ name }}</div>
</div>

The error that appears is this:

[$rootScope:inprog]

Which seems to indicate that "Digest is already running".

If you use $apply the error will be exactly the same.

So when to use $digest or $apply?

Use these guys when you need to update Angularjs values in an event that is not foreseen in Angularjs automatic synchronization.

For example, if you want to apply a logic in Angularjs that depends on the event onscroll or a mousemove, you would need to use $apply or $digest for changes to be processed, since Angularjs does not use them internally.

Behold:

angular.module('app', [])

.controller('AppController', function ($scope) {

    $scope.name = 'Wallace';
    
    angular.element(window).on('mousemove', function (e) {
    
         $scope.y = e.clientX;
    
         $scope.$digest();
    })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>

<div ng-app="app">
   <p>Me o mouse para aparecer a posição</p>
   <div ng-controller="AppController"> A posição do mouse é, {{ y }}</div>
</div>

And the $evalAsync?

On account of what I explain above is that you had to use $evalAsync. For, as Angularjs does not accept that two $digest run at the same time, you need to use the methods that make the $digest asynchronously, to force Angularjs to perform these $Watchers checks only when all other automatic calls from $digest have already been processed.

The methods as $applyAsync and $evalAsync make a small "delay" in calling $digest to avoid the error described above.

Behold:

angular.module('app', [])

.controller('AppController', function ($scope) {

    $scope.name = 'Wallace';
    
    $scope.$evalAsync(); // Ou '$applyAsync'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>

<div ng-app="app">
   <div ng-controller="AppController"> Hello, {{ name }}</div>
</div>

Notes

¹ - When you use ng-if, ng-show, ng-model, ng-class or ng-style (and anything else that works "magically" in Angularjs), you are creating a $watcher implicitly. If you use the method $scope.$watch('nome_da_variavel') you’re creating this $watcher manually. It is these Watchers that Angularjs performs in each update cycle, where the method $digestis called.

² - There is a small difference between $digest and $apply. I asked a question about that: What is the difference between $Digest and $apply?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.