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..95dbb44ed81e 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3742,6 +3742,31 @@ 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) { + element = $compile('')($rootScope); + + $rootScope.$apply('val = 1'); + expect(log.pop()).toEqual({prop1: jasmine.objectContaining({previousValue: undefined, currentValue: 1})}); + + element.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() { }