From 2d0f6ccba896fe34141d6d4f59eef6fba580c5c2 Mon Sep 17 00:00:00 2001 From: Daniel Tabuenca Date: Wed, 27 Nov 2013 22:01:22 -0800 Subject: [PATCH] fix($compile): ensure isolated local watches' lastValue is always in 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 #5182 --- src/ng/compile.js | 6 +++--- test/ng/compileSpec.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 0963b8d5d2bf..fd8a8729d87a 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -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; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 6de96f651b2e..c017bfa67e8b 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -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('
'); + + //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('
'); $rootScope.name = 'world';