I've written an AngularJS (1.x) directive that wraps a pure javascript library object, called browser.
In order to update Angular scope variables and view in response to events, occurring within browser, I have to manually call $apply, invoking the digest loop:
scope.browser.on({
afterSetRange: function(){
if (!scope.$$phase) scope.$apply();
}
});
This works fine, when my directive is not creating its own scope - I say scope: false in Directive Definition Object (DDO). In that case scope refers to the page controller's $scope.
But when I'm using an isolated scope with scope: {myattr: '='}, this apparently doesn't save me from getting:
Error: [$rootScope:inprog] $digest is already in progress
I solved this problem by replacing if (!scope.$$phase) scope.$apply with $timout(angular.noop). (This means, that scope.$apply is poorly designed - it should just work, instead of forcing people to dig in its internals). What I really want is an asnwer to the following theoretical question, not practical help:
I don't understand the theory behind $digest loop. Documentation of rootScope.$new() implies that $digest event propagates from rootScope to its children. So, do we have a single digest loop for the whole angular app? Or a loop per each scope?
And how does Angular achieve synchronization between directive attributes and controller around it, when I'm using 2-way data binding in directive (e.g. scope: {myattr: '='})?