diff --git a/src/ng/compile.js b/src/ng/compile.js
index 485d5079b254..862d7d385818 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -3213,14 +3213,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
parentGet = $parse(attrs[attrName]);
- destination[scopeName] = parentGet(scope);
+ var initialValue = destination[scopeName] = parentGet(scope);
initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
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];
+ if (oldValue === newValue) {
+ if (oldValue === initialValue) return;
+ oldValue = initialValue;
}
recordChanges(scopeName, newValue, oldValue);
destination[scopeName] = newValue;
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index d424fb42f580..e4da3d81b035 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -3823,6 +3823,7 @@ describe('$compile', function() {
$rootScope.$apply('a = 7');
element = $compile('')($rootScope);
+
expect(log).toEqual([
{
prop: jasmine.objectContaining({currentValue: 7}),
@@ -3862,6 +3863,7 @@ describe('$compile', function() {
inject(function($compile, $rootScope) {
$rootScope.$apply('a = 7');
element = $compile('')($rootScope);
+
expect(log).toEqual([
{
prop: jasmine.objectContaining({currentValue: 7}),
@@ -4744,6 +4746,7 @@ describe('$compile', function() {
describe('one-way binding', function() {
it('should update isolate when the identity of origin changes', inject(function() {
compile('
');
+
expect(componentScope.owRef).toBeUndefined();
expect(componentScope.owRefAlias).toBe(componentScope.owRef);
@@ -4780,6 +4783,7 @@ describe('$compile', function() {
it('should update isolate when both change', inject(function() {
compile('');
+
$rootScope.name = {mark:123};
componentScope.owRef = 'misko';
@@ -4796,6 +4800,101 @@ describe('$compile', function() {
expect(componentScope.owRefAlias).toBe($rootScope.name);
}));
+ describe('initialization', function() {
+ var component, log;
+
+ beforeEach(function() {
+ log = [];
+ angular.module('owComponentTest', [])
+ .component('owComponent', {
+ bindings: { input: '<' },
+ controller: function() {
+ component = this;
+ this.input = 'constructor';
+ log.push('constructor');
+
+ this.$onInit = function() {
+ this.input = '$onInit';
+ log.push('$onInit');
+ };
+
+ this.$onChanges = function(changes) {
+ if (changes.input) {
+ log.push(['$onChanges', changes.input]);
+ }
+ };
+ }
+ });
+ });
+
+ it('should not update isolate again after $onInit if outer has not changed', function() {
+ module('owComponentTest');
+ inject(function() {
+ $rootScope.name = 'outer';
+ compile('');
+
+ expect($rootScope.name).toEqual('outer');
+ expect(component.input).toEqual('$onInit');
+
+ $rootScope.$apply();
+
+ expect($rootScope.name).toEqual('outer');
+ expect(component.input).toEqual('$onInit');
+
+ expect(log).toEqual([
+ 'constructor',
+ ['$onChanges', jasmine.objectContaining({ currentValue: 'outer' })],
+ '$onInit'
+ ]);
+ });
+ });
+
+ it('should update isolate again after $onInit if outer has changed (before initial watchAction call)', function() {
+ module('owComponentTest');
+ inject(function() {
+ $rootScope.name = 'outer1';
+ compile('');
+
+ expect(component.input).toEqual('$onInit');
+ $rootScope.$apply('name = "outer2"');
+
+ expect($rootScope.name).toEqual('outer2');
+ expect(component.input).toEqual('outer2');
+ expect(log).toEqual([
+ 'constructor',
+ ['$onChanges', jasmine.objectContaining({ currentValue: 'outer1' })],
+ '$onInit',
+ ['$onChanges', jasmine.objectContaining({ currentValue: 'outer2', previousValue: 'outer1' })]
+ ]);
+ });
+ });
+
+ it('should update isolate again after $onInit if outer has changed (before initial watchAction call)', function() {
+ angular.module('owComponentTest')
+ .directive('changeInput', function() {
+ return function(scope, elem, attrs) {
+ scope.name = 'outer2';
+ };
+ });
+ module('owComponentTest');
+ inject(function() {
+ $rootScope.name = 'outer1';
+ compile('');
+
+ expect(component.input).toEqual('$onInit');
+ $rootScope.$digest();
+
+ expect($rootScope.name).toEqual('outer2');
+ expect(component.input).toEqual('outer2');
+ expect(log).toEqual([
+ 'constructor',
+ ['$onChanges', jasmine.objectContaining({ currentValue: 'outer1' })],
+ '$onInit',
+ ['$onChanges', jasmine.objectContaining({ currentValue: 'outer2', previousValue: 'outer1' })]
+ ]);
+ });
+ });
+ });
it('should not break when isolate and origin both change to the same value', inject(function() {
$rootScope.name = 'aaa';
@@ -4819,7 +4918,6 @@ describe('$compile', function() {
$rootScope.name = {mark:123};
compile('');
- $rootScope.$apply();
expect($rootScope.name).toEqual({mark:123});
expect(componentScope.owRef).toBe($rootScope.name);
expect(componentScope.owRefAlias).toBe($rootScope.name);
@@ -4836,7 +4934,6 @@ describe('$compile', function() {
$rootScope.obj = {mark:123};
compile('');
- $rootScope.$apply();
expect($rootScope.obj).toEqual({mark:123});
expect(componentScope.owRef).toBe($rootScope.obj);
@@ -4849,6 +4946,7 @@ describe('$compile', function() {
it('should not throw on non assignable expressions in the parent', inject(function() {
compile('');
+
$rootScope.name = 'world';
$rootScope.$apply();
expect(componentScope.owRef).toBe('hello world');
@@ -4865,7 +4963,7 @@ describe('$compile', function() {
it('should not throw when assigning to undefined', inject(function() {
compile('');
- $rootScope.$apply();
+
expect(componentScope.owRef).toBeUndefined();
componentScope.owRef = 'ignore me';
@@ -4879,6 +4977,7 @@ describe('$compile', function() {
it('should update isolate scope when "<"-bound NaN changes', inject(function() {
$rootScope.num = NaN;
compile('');
+
var isolateScope = element.isolateScope();
expect(isolateScope.owRef).toBeNaN();
@@ -4917,7 +5016,7 @@ describe('$compile', function() {
$rootScope.name = 'georgios';
$rootScope.obj = {name: 'pete'};
compile('');
- $rootScope.$apply();
+
expect(componentScope.owRef).toEqual([{name: 'georgios'}, {name: 'pete'}]);
$rootScope.name = 'lucas';
@@ -4931,7 +5030,7 @@ describe('$compile', function() {
$rootScope.name = 'georgios';
$rootScope.obj = {name: 'pete'};
compile('');
- $rootScope.$apply();
+
expect(componentScope.owRef).toEqual({name: 'georgios', item: {name: 'pete'}});
$rootScope.name = 'lucas';
@@ -4967,7 +5066,6 @@ describe('$compile', function() {
function test(literalString, literalValue) {
compile('');
- $rootScope.$apply();
expect(componentScope.owRef).toBe(literalValue);
dealoc(element);
}
@@ -4976,6 +5074,7 @@ describe('$compile', function() {
describe('optional one-way binding', function() {
it('should update local when origin changes', inject(function() {
compile('');
+
expect(componentScope.owOptref).toBeUndefined();
expect(componentScope.owOptrefAlias).toBe(componentScope.owOptref);