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

Commit 7e794d3

Browse files
SQUASH ME (AGAIN)
1 parent 5b1e6f6 commit 7e794d3

File tree

2 files changed

+59
-17
lines changed

2 files changed

+59
-17
lines changed

src/ng/compile.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12411241
* Increasing the TTL could have performance implications, so you should not change it without proper justification.
12421242
*
12431243
* @param {number} limit The number of `$onChanges` hook iterations.
1244-
* @returns {number|object} the current limit (or `this` if called as a setting for chaining)
1244+
* @returns {number|object} the current limit (or `this` if called as a setter for chaining)
12451245
*/
12461246
this.onChangesTtl = function(value) {
12471247
if (arguments.length) {
@@ -1269,19 +1269,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12691269

12701270
// This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
12711271
function flushOnChangesQueue() {
1272-
if (!(onChangesTtl--)) {
1273-
onChangesTtl = TTL;
1274-
throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
1275-
}
1276-
// We must run this hook in an apply since the $$postDigest runs outside apply
1277-
$rootScope.$apply(function() {
1278-
for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
1279-
onChangesQueue[i]();
1272+
try {
1273+
if (!(--onChangesTtl)) {
1274+
// We have hit the TTL limit so reset everything
1275+
onChangesQueue = undefined;
1276+
throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
12801277
}
1281-
// Reset the queue to trigger a new schedule next time there is a change
1282-
onChangesQueue = undefined;
1283-
});
1284-
onChangesTtl++;
1278+
// We must run this hook in an apply since the $$postDigest runs outside apply
1279+
$rootScope.$apply(function() {
1280+
for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
1281+
onChangesQueue[i]();
1282+
}
1283+
// Reset the queue to trigger a new schedule next time there is a change
1284+
onChangesQueue = undefined;
1285+
});
1286+
} finally {
1287+
onChangesTtl++;
1288+
}
12851289
}
12861290

12871291

@@ -3194,7 +3198,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
31943198
if (isFunction(destination.$onChanges) && currentValue !== previousValue) {
31953199
// If we have not already scheduled the top level onChangesQueue handler then do so now
31963200
if (!onChangesQueue) {
3197-
// Initialize the TTL tracker for tracking stack overflow
31983201
scope.$$postDigest(flushOnChangesQueue);
31993202
onChangesQueue = [];
32003203
}

test/ng/compileSpec.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3838,7 +3838,7 @@ describe('$compile', function() {
38383838
});
38393839

38403840

3841-
it('should throw a RangeError if `$onChanges()` hooks are not stable', function() {
3841+
it('should throw an error if `$onChanges()` hooks are not stable', function() {
38423842
function TestController() {}
38433843
TestController.prototype.$onChanges = function(change) {
38443844
this.onChange();
@@ -3856,11 +3856,50 @@ describe('$compile', function() {
38563856
// Setup the directive with bindings that will keep updating the bound value forever
38573857
element = $compile('<c1 prop="a" on-change="a = -a"></c1>')($rootScope);
38583858

3859-
// Update val to trigger the unstable onChanges, which will result in a
3860-
// Range error - maximum call stack size exceeded
3859+
// Update val to trigger the unstable onChanges, which will result in an error
38613860
expect(function() {
38623861
$rootScope.$apply('a = 42');
38633862
}).toThrowMinErr('$compile', 'infchng');
3863+
3864+
dealoc(element);
3865+
element = $compile('<c1 prop="b" on-change=""></c1>')($rootScope);
3866+
$rootScope.$apply('b = 24');
3867+
$rootScope.$apply('b = 48');
3868+
});
3869+
});
3870+
3871+
3872+
it('should log an error if `$onChanges()` hooks are not stable', function() {
3873+
function TestController() {}
3874+
TestController.prototype.$onChanges = function(change) {
3875+
this.onChange();
3876+
};
3877+
3878+
angular.module('my', [])
3879+
.component('c1', {
3880+
controller: TestController,
3881+
bindings: {'prop': '<', onChange: '&'}
3882+
})
3883+
.config(function($exceptionHandlerProvider) {
3884+
// We need to test with the exceptionHandler not rethrowing...
3885+
$exceptionHandlerProvider.mode('log');
3886+
});
3887+
3888+
module('my');
3889+
inject(function($compile, $rootScope, $exceptionHandler) {
3890+
3891+
// Setup the directive with bindings that will keep updating the bound value forever
3892+
element = $compile('<c1 prop="a" on-change="a = -a"></c1>')($rootScope);
3893+
3894+
// Update val to trigger the unstable onChanges, which will result in an error
3895+
$rootScope.$apply('a = 42');
3896+
3897+
dealoc(element);
3898+
element = $compile('<c1 prop="b" on-change=""></c1>')($rootScope);
3899+
$rootScope.$apply('b = 24');
3900+
$rootScope.$apply('b = 48');
3901+
3902+
expect($exceptionHandler.errors[0].toString()).toContain('[$compile:infchng] 10 $onChanges() iterations reached.');
38643903
});
38653904
});
38663905
});

0 commit comments

Comments
 (0)