Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 43072e3

Browse files
committed
fix($compile): Allow literals in isolate scope references
When a component uses an isolate scope reference and the the component is used with an object literal a new object is created on every evaluation. Therefore the compiler needs to compare the values of the parent and the isolate scope using object equality and not object reference equality. Fixes #5296.
1 parent 9396d55 commit 43072e3

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

src/ng/compile.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14001400
optional = (match[2] == '?'),
14011401
mode = match[1], // @, =, or &
14021402
lastValue,
1403-
parentGet, parentSet;
1403+
parentGet, parentSet, compare;
14041404

14051405
isolateScope.$$isolateBindings[scopeName] = mode + attrName;
14061406

@@ -1423,6 +1423,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14231423
return;
14241424
}
14251425
parentGet = $parse(attrs[attrName]);
1426+
if (parentGet.literal) {
1427+
compare = equals;
1428+
} else {
1429+
compare = function(a,b) { return a === b; };
1430+
}
14261431
parentSet = parentGet.assign || function() {
14271432
// reset the change, or we will throw this exception on every $digest
14281433
lastValue = isolateScope[scopeName] = parentGet(scope);
@@ -1433,10 +1438,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14331438
lastValue = isolateScope[scopeName] = parentGet(scope);
14341439
isolateScope.$watch(function parentValueWatch() {
14351440
var parentValue = parentGet(scope);
1436-
1437-
if (parentValue !== isolateScope[scopeName]) {
1441+
if (!compare(parentValue, isolateScope[scopeName])) {
14381442
// we are out of sync and need to copy
1439-
if (parentValue !== lastValue) {
1443+
if (!compare(parentValue, lastValue)) {
14401444
// parent changed and it has precedence
14411445
isolateScope[scopeName] = parentValue;
14421446
} else {
@@ -1445,7 +1449,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14451449
}
14461450
}
14471451
return lastValue = parentValue;
1448-
});
1452+
}, null, parentGet.literal);
14491453
break;
14501454

14511455
case '&':

test/ng/compileSpec.js

+56
Original file line numberDiff line numberDiff line change
@@ -2492,6 +2492,62 @@ describe('$compile', function() {
24922492

24932493
expect(lastRefValueInParent).toBe('new');
24942494
}));
2495+
2496+
describe('literal objects', function() {
2497+
it('should copy parent changes', inject(function() {
2498+
compile('<div><span my-component reference="{name: name}">');
2499+
2500+
$rootScope.name = 'a';
2501+
$rootScope.$apply();
2502+
expect(componentScope.reference).toEqual({name: 'a'});
2503+
2504+
$rootScope.name = 'b';
2505+
$rootScope.$apply();
2506+
expect(componentScope.reference).toEqual({name: 'b'});
2507+
}));
2508+
2509+
it('should not change the component when parent does not change', inject(function() {
2510+
compile('<div><span my-component reference="{name: name}">');
2511+
2512+
$rootScope.name = 'a';
2513+
$rootScope.$apply();
2514+
var lastComponentValue = componentScope.reference;
2515+
$rootScope.$apply();
2516+
expect(componentScope.reference).toBe(lastComponentValue);
2517+
}));
2518+
2519+
it('should complain when the component changes', inject(function() {
2520+
compile('<div><span my-component reference="{name: name}">');
2521+
2522+
$rootScope.name = 'a';
2523+
$rootScope.$apply();
2524+
componentScope.reference = {name: 'b'};
2525+
expect(function() {
2526+
$rootScope.$apply();
2527+
}).toThrowMinErr("$compile", "nonassign", "Expression '{name: name}' used with directive 'myComponent' is non-assignable!");
2528+
2529+
}));
2530+
2531+
it('should work for primitive literals', inject(function() {
2532+
test('1', 1);
2533+
test('null', null);
2534+
test('undefined', undefined);
2535+
test("'someString'", 'someString');
2536+
2537+
2538+
function test(literalString, literalValue) {
2539+
compile('<div><span my-component reference="'+literalString+'">');
2540+
2541+
$rootScope.$apply();
2542+
expect(componentScope.reference).toBe(literalValue);
2543+
dealoc(element);
2544+
2545+
}
2546+
2547+
}));
2548+
2549+
});
2550+
24952551
});
24962552

24972553

0 commit comments

Comments
 (0)