Skip to content

Commit c2b8fab

Browse files
committed
fix($rootScope): provide correct value of one-time bindings in watchGroup
1 parent f403925 commit c2b8fab

File tree

2 files changed

+100
-7
lines changed

2 files changed

+100
-7
lines changed

src/ng/rootScope.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -490,9 +490,8 @@ function $RootScopeProvider() {
490490
}
491491

492492
forEach(watchExpressions, function(expr, i) {
493-
var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
493+
var unwatchFn = self.$watch(expr, function watchGroupSubAction(value) {
494494
newValues[i] = value;
495-
oldValues[i] = oldValue;
496495
if (!changeReactionScheduled) {
497496
changeReactionScheduled = true;
498497
self.$evalAsync(watchGroupAction);
@@ -504,11 +503,17 @@ function $RootScopeProvider() {
504503
function watchGroupAction() {
505504
changeReactionScheduled = false;
506505

507-
if (firstRun) {
508-
firstRun = false;
509-
listener(newValues, newValues, self);
510-
} else {
511-
listener(newValues, oldValues, self);
506+
try {
507+
if (firstRun) {
508+
firstRun = false;
509+
listener(newValues, newValues, self);
510+
} else {
511+
listener(newValues, oldValues, self);
512+
}
513+
} finally {
514+
for (var i = 0; i < watchExpressions.length; i++) {
515+
oldValues[i] = newValues[i];
516+
}
512517
}
513518
}
514519

test/ng/rootScopeSpec.js

+88
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,94 @@ describe('Scope', function() {
10971097
expect(log).toEqual('');
10981098
});
10991099

1100+
it('should remove all watchers once one-time/constant bindings are stable', function() {
1101+
//empty
1102+
scope.$watchGroup([], noop);
1103+
//single one-time
1104+
scope.$watchGroup(['::a'], noop);
1105+
//multi one-time
1106+
scope.$watchGroup(['::a', '::b'], noop);
1107+
//single constant
1108+
scope.$watchGroup(['1'], noop);
1109+
//multi constant
1110+
scope.$watchGroup(['1', '2'], noop);
1111+
1112+
expect(scope.$$watchersCount).not.toBe(0);
1113+
scope.$apply('a = b = 1');
1114+
expect(scope.$$watchersCount).toBe(0);
1115+
});
1116+
1117+
it('should maintain correct new/old values with one time bindings', function() {
1118+
var newValues;
1119+
var oldValues;
1120+
scope.$watchGroup(['a', '::b', 'b', '4'], function(n, o) {
1121+
newValues = n.slice();
1122+
oldValues = o.slice();
1123+
});
1124+
1125+
scope.$apply();
1126+
expect(newValues).toEqual(oldValues);
1127+
expect(oldValues).toEqual([undefined, undefined, undefined, 4]);
1128+
1129+
scope.$apply('a = 1');
1130+
expect(newValues).toEqual([1, undefined, undefined, 4]);
1131+
expect(oldValues).toEqual([undefined, undefined, undefined, 4]);
1132+
1133+
scope.$apply('b = 2');
1134+
expect(newValues).toEqual([1, 2, 2, 4]);
1135+
expect(oldValues).toEqual([1, undefined, undefined, 4]);
1136+
1137+
scope.$apply('b = 3');
1138+
expect(newValues).toEqual([1, 2, 3, 4]);
1139+
expect(oldValues).toEqual([1, 2, 2, 4]);
1140+
1141+
scope.$apply('b = 4');
1142+
expect(newValues).toEqual([1, 2, 4, 4]);
1143+
expect(oldValues).toEqual([1, 2, 3, 4]);
1144+
});
1145+
});
1146+
1147+
describe('$watchGroup with logging $exceptionHandler', function() {
1148+
it('should maintain correct new/old values even when listener throws', function() {
1149+
module(function($exceptionHandlerProvider) {
1150+
$exceptionHandlerProvider.mode('log');
1151+
});
1152+
1153+
inject(function($rootScope, $exceptionHandler) {
1154+
var newValues;
1155+
var oldValues;
1156+
$rootScope.$watchGroup(['a', '::b', 'b', '4'], function(n, o) {
1157+
newValues = n.slice();
1158+
oldValues = o.slice();
1159+
throw 'test';
1160+
});
1161+
1162+
$rootScope.$apply();
1163+
expect(newValues).toEqual(oldValues);
1164+
expect(oldValues).toEqual([undefined, undefined, undefined, 4]);
1165+
expect($exceptionHandler.errors.length).toBe(1);
1166+
1167+
$rootScope.$apply('a = 1');
1168+
expect(newValues).toEqual([1, undefined, undefined, 4]);
1169+
expect(oldValues).toEqual([undefined, undefined, undefined, 4]);
1170+
expect($exceptionHandler.errors.length).toBe(2);
1171+
1172+
$rootScope.$apply('b = 2');
1173+
expect(newValues).toEqual([1, 2, 2, 4]);
1174+
expect(oldValues).toEqual([1, undefined, undefined, 4]);
1175+
expect($exceptionHandler.errors.length).toBe(3);
1176+
1177+
$rootScope.$apply('b = 3');
1178+
expect(newValues).toEqual([1, 2, 3, 4]);
1179+
expect(oldValues).toEqual([1, 2, 2, 4]);
1180+
expect($exceptionHandler.errors.length).toBe(4);
1181+
1182+
$rootScope.$apply('b = 4');
1183+
expect(newValues).toEqual([1, 2, 4, 4]);
1184+
expect(oldValues).toEqual([1, 2, 3, 4]);
1185+
expect($exceptionHandler.errors.length).toBe(5);
1186+
});
1187+
});
11001188
});
11011189

11021190
describe('$destroy', function() {

0 commit comments

Comments
 (0)