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

Commit 7504656

Browse files
committed
fix($parse): do not shallow-watch computed property keys
Shallow watching is not enough when an object implements a non-pure toString
1 parent e74cdf4 commit 7504656

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

src/ng/parse.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,8 @@ function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
744744
allConstants = allConstants && property.value.constant;
745745
argsToWatch.push.apply(argsToWatch, property.value.toWatch);
746746
if (property.computed) {
747-
findConstantAndWatchExpressions(property.key, $filter, astIsPure);
747+
//`{[key]: value}` implicitly does `key.toString()` which may be non-pure
748+
findConstantAndWatchExpressions(property.key, $filter, /*parentIsPure=*/false);
748749
allConstants = allConstants && property.key.constant;
749750
argsToWatch.push.apply(argsToWatch, property.key.toWatch);
750751
}

test/ng/parseSpec.js

+28-8
Original file line numberDiff line numberDiff line change
@@ -3568,35 +3568,55 @@ describe('parser', function() {
35683568

35693569
it('should watch ES6 object computed property changes', function() {
35703570
var count = 0;
3571-
var values = [];
3571+
var lastValue;
35723572

35733573
scope.$watch('{[a]: true}', function(val) {
35743574
count++;
3575-
values.push(val);
3576-
}, true);
3575+
lastValue = val;
3576+
});
35773577

35783578
scope.$digest();
35793579
expect(count).toBe(1);
3580-
expect(values[0]).toEqual({'undefined': true});
3580+
expect(lastValue).toEqual({'undefined': true});
35813581

35823582
scope.$digest();
35833583
expect(count).toBe(1);
3584-
expect(values[0]).toEqual({'undefined': true});
3584+
expect(lastValue).toEqual({'undefined': true});
35853585

35863586
scope.a = true;
35873587
scope.$digest();
35883588
expect(count).toBe(2);
3589-
expect(values[1]).toEqual({'true': true});
3589+
expect(lastValue).toEqual({'true': true});
35903590

35913591
scope.a = 'abc';
35923592
scope.$digest();
35933593
expect(count).toBe(3);
3594-
expect(values[2]).toEqual({'abc': true});
3594+
expect(lastValue).toEqual({'abc': true});
35953595

35963596
scope.a = undefined;
35973597
scope.$digest();
35983598
expect(count).toBe(4);
3599-
expect(values[3]).toEqual({'undefined': true});
3599+
expect(lastValue).toEqual({'undefined': true});
3600+
});
3601+
3602+
it('should not shallow-watch ES6 object computed properties in case of stateful toString', function() {
3603+
var count = 0;
3604+
var lastValue;
3605+
3606+
scope.$watch('{[a]: true}', function(val) {
3607+
count++;
3608+
lastValue = val;
3609+
});
3610+
3611+
scope.a = {toString: function() { return this.b; }};
3612+
scope.a.b = 1;
3613+
3614+
//TODO: would be great if it didn't throw!
3615+
expect(function() { scope.$apply(); }).toThrowMinErr('$rootScope', 'infdig');
3616+
expect(lastValue).toEqual({1: true});
3617+
3618+
expect(function() { scope.$apply('a.b = 2'); }).toThrowMinErr('$rootScope', 'infdig');
3619+
expect(lastValue).toEqual({2: true});
36003620
});
36013621
});
36023622

0 commit comments

Comments
 (0)