Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 6b0193e

Browse files
markgardnerNarretz
authored andcommitted
fix(ngEventDirs): don't wrap the event handler in $apply if already in $digest
Digest cycle already in progress error can inadvertently be caused when triggering an element's click event while within an active digest cycle. This is due to the ngEventsDirs event handler always calling $rootScope.$apply regardless of the status of $rootScope.$$phase. Checking the phase and calling the function immediately if within an active digest cycle will prevent the problem without reducing current functionality. Closes #14673 Closes #14674
1 parent e500fb6 commit 6b0193e

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

src/ng/directive/ngEventDirs.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@ forEach(
6464
var callback = function() {
6565
fn(scope, {$event: event});
6666
};
67-
if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
67+
if (!$rootScope.$$phase) {
68+
scope.$apply(callback);
69+
} else if (forceAsyncEvents[eventName]) {
6870
scope.$evalAsync(callback);
6971
} else {
70-
scope.$apply(callback);
72+
callback();
7173
}
7274
});
7375
};

test/ng/directive/ngEventDirsSpec.js

+40
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,44 @@ describe('event directives', function() {
150150
}));
151151

152152
});
153+
154+
155+
it('should call the listener synchronously if the event is triggered inside of a digest',
156+
inject(function($rootScope, $compile) {
157+
var watchedVal;
158+
159+
element = $compile('<button type="button" ng-click="click()">Button</button>')($rootScope);
160+
$rootScope.$watch('value', function(newValue) {
161+
watchedVal = newValue;
162+
});
163+
$rootScope.click = jasmine.createSpy('click').and.callFake(function() {
164+
$rootScope.value = 'newValue';
165+
});
166+
167+
$rootScope.$apply(function() {
168+
element.triggerHandler('click');
169+
});
170+
171+
expect($rootScope.click).toHaveBeenCalledOnce();
172+
expect(watchedVal).toEqual('newValue');
173+
}));
174+
175+
176+
it('should call the listener synchronously if the event is triggered outside of a digest',
177+
inject(function($rootScope, $compile) {
178+
var watchedVal;
179+
180+
element = $compile('<button type="button" ng-click="click()">Button</button>')($rootScope);
181+
$rootScope.$watch('value', function(newValue) {
182+
watchedVal = newValue;
183+
});
184+
$rootScope.click = jasmine.createSpy('click').and.callFake(function() {
185+
$rootScope.value = 'newValue';
186+
});
187+
188+
element.triggerHandler('click');
189+
190+
expect($rootScope.click).toHaveBeenCalledOnce();
191+
expect(watchedVal).toEqual('newValue');
192+
}));
153193
});

0 commit comments

Comments
 (0)