Skip to content

Commit

Permalink
fix($parse): do not shallow-watch computed property keys
Browse files Browse the repository at this point in the history
Shallow watching is not enough when an object implements a non-pure toString
  • Loading branch information
jbedard committed Jul 18, 2017
1 parent 341f8db commit 631076a
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
3 changes: 2 additions & 1 deletion src/ng/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,8 @@ function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
allConstants = allConstants && property.value.constant;
argsToWatch.push.apply(argsToWatch, property.value.toWatch);
if (property.computed) {
findConstantAndWatchExpressions(property.key, $filter, astIsPure);
//`{[key]: value}` implicitly does `key.toString()` which may be non-pure
findConstantAndWatchExpressions(property.key, $filter, /*parentIsPure=*/false);
allConstants = allConstants && property.key.constant;
argsToWatch.push.apply(argsToWatch, property.key.toWatch);
}
Expand Down
36 changes: 28 additions & 8 deletions test/ng/parseSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3805,35 +3805,55 @@ describe('parser', function() {

it('should watch ES6 object computed property changes', function() {
var count = 0;
var values = [];
var lastValue;

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

scope.$digest();
expect(count).toBe(1);
expect(values[0]).toEqual({'undefined': true});
expect(lastValue).toEqual({'undefined': true});

scope.$digest();
expect(count).toBe(1);
expect(values[0]).toEqual({'undefined': true});
expect(lastValue).toEqual({'undefined': true});

scope.a = true;
scope.$digest();
expect(count).toBe(2);
expect(values[1]).toEqual({'true': true});
expect(lastValue).toEqual({'true': true});

scope.a = 'abc';
scope.$digest();
expect(count).toBe(3);
expect(values[2]).toEqual({'abc': true});
expect(lastValue).toEqual({'abc': true});

scope.a = undefined;
scope.$digest();
expect(count).toBe(4);
expect(values[3]).toEqual({'undefined': true});
expect(lastValue).toEqual({'undefined': true});
});

it('should not shallow-watch ES6 object computed properties in case of stateful toString', function() {
var count = 0;
var lastValue;

scope.$watch('{[a]: true}', function(val) {
count++;
lastValue = val;
});

scope.a = {toString: function() { return this.b; }};
scope.a.b = 1;

//TODO: would be great if it didn't throw!
expect(function() { scope.$apply(); }).toThrowMinErr('$rootScope', 'infdig');
expect(lastValue).toEqual({1: true});

expect(function() { scope.$apply('a.b = 2'); }).toThrowMinErr('$rootScope', 'infdig');
expect(lastValue).toEqual({2: true});
});
});

Expand Down

0 comments on commit 631076a

Please sign in to comment.