Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 69f1ebd

Browse files
committedJul 7, 2015
revert "revert: "fix($compile): do not write @-bound properties if attribute is not present""
This reverts commit d193c3a.
1 parent d518a64 commit 69f1ebd

File tree

2 files changed

+124
-27
lines changed

2 files changed

+124
-27
lines changed
 

‎src/ng/compile.js

+12-15
Original file line numberDiff line numberDiff line change
@@ -2567,36 +2567,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
25672567
lastValue,
25682568
parentGet, parentSet, compare;
25692569

2570-
if (!hasOwnProperty.call(attrs, attrName)) {
2571-
// In the case of user defined a binding with the same name as a method in Object.prototype but didn't set
2572-
// the corresponding attribute. We need to make sure subsequent code won't access to the prototype function
2573-
attrs[attrName] = undefined;
2574-
}
2575-
25762570
switch (mode) {
25772571

25782572
case '@':
2579-
if (!attrs[attrName] && !optional) {
2580-
destination[scopeName] = undefined;
2573+
if (!optional && !hasOwnProperty.call(attrs, attrName)) {
2574+
destination[scopeName] = attrs[attrName] = void 0;
25812575
}
2582-
25832576
attrs.$observe(attrName, function(value) {
2584-
destination[scopeName] = value;
2577+
if (isString(value)) {
2578+
destination[scopeName] = value;
2579+
}
25852580
});
25862581
attrs.$$observers[attrName].$$scope = scope;
2587-
if (attrs[attrName]) {
2582+
if (isString(attrs[attrName])) {
25882583
// If the attribute has been provided then we trigger an interpolation to ensure
25892584
// the value is there for use in the link fn
25902585
destination[scopeName] = $interpolate(attrs[attrName])(scope);
25912586
}
25922587
break;
25932588

25942589
case '=':
2595-
if (optional && !attrs[attrName]) {
2596-
return;
2590+
if (!hasOwnProperty.call(attrs, attrName)) {
2591+
if (optional) break;
2592+
attrs[attrName] = void 0;
25972593
}
2598-
parentGet = $parse(attrs[attrName]);
25992594

2595+
parentGet = $parse(attrs[attrName]);
26002596
if (parentGet.literal) {
26012597
compare = equals;
26022598
} else {
@@ -2635,7 +2631,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
26352631
break;
26362632

26372633
case '&':
2638-
parentGet = $parse(attrs[attrName]);
2634+
// Don't assign Object.prototype method to scope
2635+
parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
26392636

26402637
// Don't assign noop to destination if expression is not valid
26412638
if (parentGet === noop && optional) break;

‎test/ng/compileSpec.js

+112-12
Original file line numberDiff line numberDiff line change
@@ -2543,10 +2543,17 @@ describe('$compile', function() {
25432543
};
25442544

25452545
expect(func).not.toThrow();
2546-
expect(element.find('span').scope()).toBe(element.isolateScope());
2547-
expect(element.isolateScope()).not.toBe($rootScope);
2548-
expect(element.isolateScope()['constructor']).toBe($rootScope.constructor);
2549-
expect(element.isolateScope()['valueOf']).toBeUndefined();
2546+
var scope = element.isolateScope();
2547+
expect(element.find('span').scope()).toBe(scope);
2548+
expect(scope).not.toBe($rootScope);
2549+
2550+
// Not shadowed because optional
2551+
expect(scope.constructor).toBe($rootScope.constructor);
2552+
expect(scope.hasOwnProperty('constructor')).toBe(false);
2553+
2554+
// Shadowed with undefined because not optional
2555+
expect(scope.valueOf).toBeUndefined();
2556+
expect(scope.hasOwnProperty('valueOf')).toBe(true);
25502557
})
25512558
);
25522559

@@ -2561,10 +2568,13 @@ describe('$compile', function() {
25612568
};
25622569

25632570
expect(func).not.toThrow();
2564-
expect(element.find('span').scope()).toBe(element.isolateScope());
2565-
expect(element.isolateScope()).not.toBe($rootScope);
2566-
expect(element.isolateScope()['constructor']).toBe('constructor');
2567-
expect(element.isolateScope()['valueOf']).toBe('valueOf');
2571+
var scope = element.isolateScope();
2572+
expect(element.find('span').scope()).toBe(scope);
2573+
expect(scope).not.toBe($rootScope);
2574+
expect(scope.constructor).toBe('constructor');
2575+
expect(scope.hasOwnProperty('constructor')).toBe(true);
2576+
expect(scope.valueOf).toBe('valueOf');
2577+
expect(scope.hasOwnProperty('valueOf')).toBe(true);
25682578
})
25692579
);
25702580

@@ -2575,10 +2585,17 @@ describe('$compile', function() {
25752585
};
25762586

25772587
expect(func).not.toThrow();
2578-
expect(element.find('span').scope()).toBe(element.isolateScope());
2579-
expect(element.isolateScope()).not.toBe($rootScope);
2580-
expect(element.isolateScope()['constructor']).toBe($rootScope.constructor);
2581-
expect(element.isolateScope()['valueOf']).toBeUndefined();
2588+
var scope = element.isolateScope();
2589+
expect(element.find('span').scope()).toBe(scope);
2590+
expect(scope).not.toBe($rootScope);
2591+
2592+
// Does not shadow value because optional
2593+
expect(scope.constructor).toBe($rootScope.constructor);
2594+
expect(scope.hasOwnProperty('constructor')).toBe(false);
2595+
2596+
// Shadows value because not optional
2597+
expect(scope.valueOf).toBeUndefined();
2598+
expect(scope.hasOwnProperty('valueOf')).toBe(true);
25822599
})
25832600
);
25842601

@@ -3576,6 +3593,31 @@ describe('$compile', function() {
35763593
}));
35773594

35783595

3596+
it('should not overwrite @-bound property each digest when not present', function() {
3597+
module(function($compileProvider) {
3598+
$compileProvider.directive('testDir', valueFn({
3599+
scope: {prop: '@'},
3600+
controller: function($scope) {
3601+
$scope.prop = $scope.prop || 'default';
3602+
this.getProp = function() {
3603+
return $scope.prop;
3604+
};
3605+
},
3606+
controllerAs: 'ctrl',
3607+
template: '<p></p>'
3608+
}));
3609+
});
3610+
inject(function($compile, $rootScope) {
3611+
element = $compile('<div test-dir></div>')($rootScope);
3612+
var scope = element.isolateScope();
3613+
expect(scope.ctrl.getProp()).toBe('default');
3614+
3615+
$rootScope.$digest();
3616+
expect(scope.ctrl.getProp()).toBe('default');
3617+
});
3618+
});
3619+
3620+
35793621
describe('bind-once', function() {
35803622

35813623
function countWatches(scope) {
@@ -4437,6 +4479,64 @@ describe('$compile', function() {
44374479
childScope.theCtrl.test();
44384480
});
44394481
});
4482+
4483+
describe('should not overwrite @-bound property each digest when not present', function() {
4484+
it('when creating new scope', function() {
4485+
module(function($compileProvider) {
4486+
$compileProvider.directive('testDir', valueFn({
4487+
scope: true,
4488+
bindToController: {
4489+
prop: '@'
4490+
},
4491+
controller: function() {
4492+
var self = this;
4493+
this.prop = this.prop || 'default';
4494+
this.getProp = function() {
4495+
return self.prop;
4496+
};
4497+
},
4498+
controllerAs: 'ctrl',
4499+
template: '<p></p>'
4500+
}));
4501+
});
4502+
inject(function($compile, $rootScope) {
4503+
element = $compile('<div test-dir></div>')($rootScope);
4504+
var scope = element.scope();
4505+
expect(scope.ctrl.getProp()).toBe('default');
4506+
4507+
$rootScope.$digest();
4508+
expect(scope.ctrl.getProp()).toBe('default');
4509+
});
4510+
});
4511+
4512+
it('when creating isolate scope', function() {
4513+
module(function($compileProvider) {
4514+
$compileProvider.directive('testDir', valueFn({
4515+
scope: {},
4516+
bindToController: {
4517+
prop: '@'
4518+
},
4519+
controller: function() {
4520+
var self = this;
4521+
this.prop = this.prop || 'default';
4522+
this.getProp = function() {
4523+
return self.prop;
4524+
};
4525+
},
4526+
controllerAs: 'ctrl',
4527+
template: '<p></p>'
4528+
}));
4529+
});
4530+
inject(function($compile, $rootScope) {
4531+
element = $compile('<div test-dir></div>')($rootScope);
4532+
var scope = element.isolateScope();
4533+
expect(scope.ctrl.getProp()).toBe('default');
4534+
4535+
$rootScope.$digest();
4536+
expect(scope.ctrl.getProp()).toBe('default');
4537+
});
4538+
});
4539+
});
44404540
});
44414541

44424542

0 commit comments

Comments
 (0)