Skip to content

Commit a42f8a0

Browse files
committed
fix(ngEventDirs): pass error in handler to $exceptionHandler when event was triggered in a digest
This ensures that the error handling is the same for events triggered inside and outside a digest.
1 parent 6b0193e commit a42f8a0

File tree

2 files changed

+95
-3
lines changed

2 files changed

+95
-3
lines changed

src/ng/directive/ngEventDirs.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ forEach(
5050
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
5151
function(eventName) {
5252
var directiveName = directiveNormalize('ng-' + eventName);
53-
ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
53+
ngEventDirectives[directiveName] = ['$parse', '$rootScope', '$exceptionHandler', function($parse, $rootScope, $exceptionHandler) {
5454
return {
5555
restrict: 'A',
5656
compile: function($element, attr) {
@@ -64,12 +64,17 @@ forEach(
6464
var callback = function() {
6565
fn(scope, {$event: event});
6666
};
67+
6768
if (!$rootScope.$$phase) {
6869
scope.$apply(callback);
6970
} else if (forceAsyncEvents[eventName]) {
7071
scope.$evalAsync(callback);
7172
} else {
72-
callback();
73+
try {
74+
callback();
75+
} catch (error) {
76+
$exceptionHandler(error);
77+
}
7378
}
7479
});
7580
};

test/ng/directive/ngEventDirsSpec.js

+88-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ describe('event directives', function() {
148148
expect($rootScope.blur).toHaveBeenCalledOnce();
149149
expect(element.val()).toBe('newValue');
150150
}));
151-
152151
});
153152

154153

@@ -190,4 +189,92 @@ describe('event directives', function() {
190189
expect($rootScope.click).toHaveBeenCalledOnce();
191190
expect(watchedVal).toEqual('newValue');
192191
}));
192+
193+
194+
describe('throwing errors in event handlers', function() {
195+
196+
it('should not stop execution if the event is triggered outside a digest', function() {
197+
198+
module(function($exceptionHandlerProvider) {
199+
$exceptionHandlerProvider.mode('log');
200+
});
201+
202+
inject(function($rootScope, $compile, $exceptionHandler, $log) {
203+
204+
element = $compile('<button ng-click="click()">Click</button>')($rootScope);
205+
expect($log.assertEmpty());
206+
$rootScope.click = function() {
207+
throw new Error('listener error');
208+
};
209+
210+
$rootScope.do = function() {
211+
element.triggerHandler('click');
212+
$log.log('done');
213+
};
214+
215+
$rootScope.do();
216+
217+
expect($exceptionHandler.errors).toEqual([Error('listener error')]);
218+
expect($log.log.logs).toEqual([['done']]);
219+
$log.reset();
220+
});
221+
});
222+
223+
224+
it('should not stop execution if the event is triggered inside a digest', function() {
225+
226+
module(function($exceptionHandlerProvider) {
227+
$exceptionHandlerProvider.mode('log');
228+
});
229+
230+
inject(function($rootScope, $compile, $exceptionHandler, $log) {
231+
232+
element = $compile('<button ng-click="click()">Click</button>')($rootScope);
233+
expect($log.assertEmpty());
234+
$rootScope.click = function() {
235+
throw new Error('listener error');
236+
};
237+
238+
$rootScope.do = function() {
239+
element.triggerHandler('click');
240+
$log.log('done');
241+
};
242+
243+
$rootScope.$apply(function() {
244+
$rootScope.do();
245+
});
246+
247+
expect($exceptionHandler.errors).toEqual([Error('listener error')]);
248+
expect($log.log.logs).toEqual([['done']]);
249+
$log.reset();
250+
});
251+
});
252+
253+
254+
it('should not stop execution if the event is triggered in a watch expression function', function() {
255+
256+
module(function($exceptionHandlerProvider) {
257+
$exceptionHandlerProvider.mode('log');
258+
});
259+
260+
inject(function($rootScope, $compile, $exceptionHandler, $log) {
261+
262+
element = $compile('<button ng-click="click()">Click</button>')($rootScope);
263+
$rootScope.click = function() {
264+
throw new Error('listener error');
265+
};
266+
267+
$rootScope.$watch(function() {
268+
element.triggerHandler('click');
269+
$log.log('done');
270+
});
271+
272+
$rootScope.$digest();
273+
274+
expect($exceptionHandler.errors).toEqual([Error('listener error'), Error('listener error')]);
275+
expect($log.log.logs).toEqual([['done'], ['done']]);
276+
$log.reset();
277+
});
278+
});
279+
});
193280
});

0 commit comments

Comments
 (0)