Skip to content

Commit

Permalink
fix($compile): ensure isolated local watches' lastValue is always in …
Browse files Browse the repository at this point in the history
…sync

When using two-way binding with isolate scope, under some circumstances
the lastValue variable captured in the parentValueWatch function can get
out of sync.

Specifically, if both the value in the origin scope as well as the value
in the isolate scope get independently updated to the same value within
one digest cycle, the lastValue is never updated. This potentially causes
the watch to make the wrong decision as to which side to update on subsequent
passes.

This fixes things by ensuring lastValue is always set to the last seen
value even if the watch's logic was short circuited because there was no
difference between the values in the original and isolate scopes.

Closes angular#5182
  • Loading branch information
Daniel Tabuenca authored and jamesdaily committed Jan 27, 2014
1 parent 223bf6f commit 3577222
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1438,13 +1438,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// we are out of sync and need to copy
if (parentValue !== lastValue) {
// parent changed and it has precedence
lastValue = isolateScope[scopeName] = parentValue;
isolateScope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
parentSet(scope, parentValue = isolateScope[scopeName]);
}
}
return parentValue;
return lastValue = parentValue;
});
break;

Expand Down
18 changes: 18 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2386,6 +2386,24 @@ describe('$compile', function() {
expect(componentScope.refAlias).toBe($rootScope.name);
}));

it('should not break if local and origin both change to the same value', inject(function() {
$rootScope.name = 'aaa';

compile('<div><span my-component ref="name">');

//change both sides to the same item withing the same digest cycle
componentScope.ref = 'same';
$rootScope.name = 'same';
$rootScope.$apply();

//change origin back to it's previous value
$rootScope.name = 'aaa';
$rootScope.$apply();

expect($rootScope.name).toBe('aaa');
expect(componentScope.ref).toBe('aaa');
}));

it('should complain on non assignable changes', inject(function() {
compile('<div><span my-component ref="\'hello \' + name">');
$rootScope.name = 'world';
Expand Down

0 comments on commit 3577222

Please sign in to comment.