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

fix($parse): handle constants as one-time binding expressions #7970

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/ng/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -1027,11 +1027,7 @@ function $ParseProvider() {
cache[exp] = parsedExpression;
}

if (parsedExpression.constant) {
parsedExpression.$$unwatch = true;
}

return oneTime ? oneTimeWrapper(parsedExpression) : parsedExpression;
return oneTime || parsedExpression.constant ? oneTimeWrapper(parsedExpression) : parsedExpression;

case 'function':
return exp;
Expand All @@ -1050,7 +1046,7 @@ function $ParseProvider() {

function oneTimeParseFn(self, locals) {
if (!stable) {
lastValue = expression(self, locals);
lastValue = expression.constant && lastValue ? lastValue : expression(self, locals);
oneTimeParseFn.$$unwatch = isDefined(lastValue);
if (oneTimeParseFn.$$unwatch && self && self.$$postDigestQueue) {
self.$$postDigestQueue.push(function () {
Expand Down
9 changes: 9 additions & 0 deletions test/ng/rootScopeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ describe('Scope', function() {
expect($rootScope.$$watchers.length).toEqual(0);
}));

it('should not keep constant literals on the watch queue', inject(function($rootScope) {
$rootScope.$watch('[]', function() {});
$rootScope.$watch('{}', function() {});
expect($rootScope.$$watchers.length).toEqual(2);
$rootScope.$digest();

expect($rootScope.$$watchers.length).toEqual(0);
}));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe objects/arrays containing references to scope should be tested so that we don't lose bindings to them? Or is it already covered?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"references to scope"? can you provide an example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something along the lines:

var handledFoo;
$rootScope.foo = 'bar';
$rootScope.$watch('[2, foo, "c"]', function(value) {
    handledFoo = value[1];
}, true);
$rootScope.$digest();
expect(handledFoo).toBe('bar');
$rootScope.foo = 'baz';
$rootScope.$digest();
expect(handledFoo).toBe('baz');

I guess other tests can be already checking that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that really testing if $parse reports [2, foo, "c"] as a constant or not?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodyhaddad Yes, basically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mzgol you cannot watch a non-constant literal expression without specifying objectEquality = true without triggering a digest issue. This was the case before the one-time binding patch and now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

it('should clean up stable watches on the watch queue', inject(function($rootScope, $parse) {
$rootScope.$watch($parse('::foo'), function() {});
expect($rootScope.$$watchers.length).toEqual(1);
Expand Down