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 $digest
is called.
² - There is a small difference between $digest
and $apply
. I asked a question about that: What is the difference between $Digest and $apply?
Well, I know that the
$digest
do Angularjs does not accept that two run at the same time. When you putasync
, It’s like you’re "scheduling" the evaluation for the cystic pOxymo– Wallace Maxters
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 ?
– Christian Viana
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 theonscroll
window.– Wallace Maxters
Thank you very much, problem already solved.
– Christian Viana