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

Commit 63ce920

Browse files
fix($compile): cope with $onInit hooks throwing
Previously, if one of these hooks threw an error, then the compilation was terminated unceremoniously. Closes #14444
1 parent 5813f4f commit 63ce920

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

src/ng/compile.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
13001300
for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
13011301
try {
13021302
onChangesQueue[i]();
1303-
} catch(e) {
1303+
} catch (e) {
13041304
errors.push(e);
13051305
}
13061306
}
@@ -2471,12 +2471,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
24712471
if (isFunction(controllerInstance.$onChanges)) {
24722472
try {
24732473
controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
2474-
} catch(e) {
2474+
} catch (e) {
24752475
$exceptionHandler(e);
24762476
}
24772477
}
24782478
if (isFunction(controllerInstance.$onInit)) {
2479-
controllerInstance.$onInit();
2479+
try {
2480+
controllerInstance.$onInit();
2481+
} catch (e) {
2482+
$exceptionHandler(e);
2483+
}
24802484
}
24812485
if (isFunction(controllerInstance.$onDestroy)) {
24822486
controllerScope.$on('$destroy', function callOnDestroyHook() {

test/ng/compileSpec.js

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
fdescribe('$compile', function() {
3+
describe('$compile', function() {
44
function isUnknownElement(el) {
55
return !!el.toString().match(/Unknown/);
66
}
@@ -3563,6 +3563,46 @@ fdescribe('$compile', function() {
35633563
expect(Controller2.prototype.$onInit).toHaveBeenCalledOnce();
35643564
});
35653565
});
3566+
3567+
it('should continue to trigger other `$onInit` hooks if one throws an error', function() {
3568+
function ThrowingController() {
3569+
this.$onInit = function() {
3570+
throw new Error('bad hook');
3571+
};
3572+
}
3573+
function LoggingController($log) {
3574+
this.$onInit = function() {
3575+
$log.info('onInit');
3576+
};
3577+
}
3578+
3579+
angular.module('my', [])
3580+
.component('c1', {
3581+
controller: ThrowingController,
3582+
bindings: {'prop': '<'}
3583+
})
3584+
.component('c2', {
3585+
controller: LoggingController,
3586+
bindings: {'prop': '<'}
3587+
})
3588+
.config(function($exceptionHandlerProvider) {
3589+
// We need to test with the exceptionHandler not rethrowing...
3590+
$exceptionHandlerProvider.mode('log');
3591+
});
3592+
3593+
module('my');
3594+
inject(function($compile, $rootScope, $exceptionHandler, $log) {
3595+
3596+
// Setup the directive with bindings that will keep updating the bound value forever
3597+
element = $compile('<div><c1 prop="a"></c1><c2 prop="a"></c2>')($rootScope);
3598+
3599+
// The first component's error should be logged
3600+
expect($exceptionHandler.errors.pop().toString()).toEqual('Error: bad hook');
3601+
3602+
// The second component's hook should still be called
3603+
expect($log.info.logs.pop()).toEqual(['onInit']);
3604+
});
3605+
});
35663606
});
35673607

35683608

@@ -4113,7 +4153,9 @@ fdescribe('$compile', function() {
41134153
$rootScope.$apply('a = 42');
41144154

41154155
// Both component's error should be logged
4116-
expect($exceptionHandler.errors[0]).toEqual([new Error('bad hook: 42'), new Error('bad hook: 84')]);
4156+
var errors = $exceptionHandler.errors.pop();
4157+
expect(errors.pop()).toEqual(new Error('bad hook: 84'));
4158+
expect(errors.pop()).toEqual(new Error('bad hook: 42'));
41174159
});
41184160
});
41194161
});

0 commit comments

Comments
 (0)