From f751fad96df7a1096ec5c105d935e3212f1db1b3 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Sun, 10 Apr 2016 08:11:56 +0100 Subject: [PATCH 1/2] fix($compile): still trigger `$onChanges` even if the inner value already matches the new value --- src/ng/compile.js | 14 +++++++++----- test/ng/compileSpec.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 3078fa16e410..cdbc48e8385f 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -3197,10 +3197,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { destination[scopeName] = parentGet(scope); initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]); - removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) { - var oldValue = destination[scopeName]; - recordChanges(scopeName, newParentValue, oldValue); - destination[scopeName] = newParentValue; + removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) { + if (newValue === oldValue) { + // If the new and old values are identical then this is the first time the watch has been triggered + // So instead we use the current value on the destination as the old value + oldValue = destination[scopeName]; + } + recordChanges(scopeName, newValue, oldValue); + destination[scopeName] = newValue; }, parentGet.literal); removeWatchCollection.push(removeWatch); @@ -3233,7 +3237,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { onChangesQueue.push(triggerOnChangesHook); } // If the has been a change on this property already then we need to reuse the previous value - if (changes[key]) { + if (isDefined(changes[key])) { previousValue = changes[key].previousValue; } // Store this change diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 624852531874..3be3fb4c20f0 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3742,6 +3742,34 @@ describe('$compile', function() { }); + it('should trigger `$onChanges` even if the inner value already equals the new outer value', function() { + var log = []; + function TestController() { } + TestController.prototype.$onChanges = function(change) { log.push(change); }; + + angular.module('my', []) + .component('c1', { + controller: TestController, + bindings: { 'prop1': '<' } + }); + + module('my'); + inject(function($compile, $rootScope) { + $rootScope.getVal = function() { return $rootScope.val; }; + element = $compile('')($rootScope); + var isolateScope = element.isolateScope(); + + log = []; + $rootScope.$apply('val = 1'); + expect(log.pop()).toEqual({prop1: jasmine.objectContaining({previousValue: undefined, currentValue: 1})}); + + isolateScope.$ctrl.prop1 = 2; + $rootScope.$apply('val = 2'); + expect(log.pop()).toEqual({prop1: jasmine.objectContaining({previousValue: 1, currentValue: 2})}); + }); + }); + + it('should pass the original value as `previousValue` even if there were multiple changes in a single digest', function() { var log = []; function TestController() { } From d8c84b444a4d8cdf9413698633708cf3ce6c62da Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Sun, 10 Apr 2016 16:05:34 +0100 Subject: [PATCH 2/2] fix($compile): still trigger `$onChanges` even if the inner value already matches the new value --- test/ng/compileSpec.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 3be3fb4c20f0..95dbb44ed81e 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3755,15 +3755,12 @@ describe('$compile', function() { module('my'); inject(function($compile, $rootScope) { - $rootScope.getVal = function() { return $rootScope.val; }; element = $compile('')($rootScope); - var isolateScope = element.isolateScope(); - log = []; $rootScope.$apply('val = 1'); expect(log.pop()).toEqual({prop1: jasmine.objectContaining({previousValue: undefined, currentValue: 1})}); - isolateScope.$ctrl.prop1 = 2; + element.isolateScope().$ctrl.prop1 = 2; $rootScope.$apply('val = 2'); expect(log.pop()).toEqual({prop1: jasmine.objectContaining({previousValue: 1, currentValue: 2})}); });