I'm building a complex hybrid app and have been testing on a real device. Occasionally, I'm getting the dreaded $digest already in progress
error from Angular - especially, it appears to be after a somewhat long digest cycle. From the stack trace it appears to be initiated from an Angular defer function that updates the location.href, which then triggers fastclick to send a touchend that in turn triggers a second digest leading to the error. Has anyone experienced this same error - and if so, how did you go about resolving it?
For those interested, here is what I am seeing in the stacktrace:
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.3.0/$rootScope/inprog?p0=%24digest:
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:80:32
beginPhase@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:14473:31
$apply@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:14220:21
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:22523:29
eventHandler@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:3013:25
dispatchEvent@sendClick@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/fastclick/fastclick.js:295:30
onTouchEnd@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/fastclick/fastclick.js:589:18
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/fastclick/fastclick.js:105:43
url@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:5022:19
setBrowserUrlWithFallback@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:11080:21
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:11186:40
$eval@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:14123:28
$digest@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:13939:36
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:14161:33
completeOutstandingRequest@file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:4877:15
file:///private/var/mobile/Containers/Bundle/Application/4040564A-5631-4A1A-B2FD-6E53F9A574F2/test.app/www/js/3rdparty/angular/angular.js:5250:33
Here's the havoc wreaker (source link):
FastClick.prototype.sendClick = function(targetElement, event) {
// ... some lines skipped
clickEvent = document.createEvent('MouseEvents');
clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent); // got you!
};
The problem is that the handler for the artificial click
will be fired immediately (demo). That's usually fine - but not with Angular, because touchEnd
event has been generated within $digest
phase, and ng-click
seems to be somewhat optimistic about events it has to process with its $apply
code. Hence the $digest
ka-boom.
Anyway, this thing seems to be pretty fixable: just async the event dispatch! One, rather straightforward way is replacing the got you!
line with something like...
setTimeout(function() {
targetElement.dispatchEvent(clickEvent);
}, 0);
Seems to work in our case, at least. )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With