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

Commit

Permalink
fix($compile): Allow literals in isolate scope references
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tbosch committed Dec 13, 2013
1 parent 9396d55 commit 43072e3
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 5 deletions.
14 changes: 9 additions & 5 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
optional = (match[2] == '?'),
mode = match[1], // @, =, or &
lastValue,
parentGet, parentSet;
parentGet, parentSet, compare;

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

Expand All @@ -1423,6 +1423,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return;
}
parentGet = $parse(attrs[attrName]);
if (parentGet.literal) {
compare = equals;
} else {
compare = function(a,b) { return a === b; };
}
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
lastValue = isolateScope[scopeName] = parentGet(scope);
Expand All @@ -1433,10 +1438,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
lastValue = isolateScope[scopeName] = parentGet(scope);
isolateScope.$watch(function parentValueWatch() {
var parentValue = parentGet(scope);

if (parentValue !== isolateScope[scopeName]) {
if (!compare(parentValue, isolateScope[scopeName])) {
// we are out of sync and need to copy
if (parentValue !== lastValue) {
if (!compare(parentValue, lastValue)) {
// parent changed and it has precedence
isolateScope[scopeName] = parentValue;
} else {
Expand All @@ -1445,7 +1449,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
return lastValue = parentValue;
});
}, null, parentGet.literal);
break;

case '&':
Expand Down
56 changes: 56 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,62 @@ describe('$compile', function() {

expect(lastRefValueInParent).toBe('new');
}));

describe('literal objects', function() {
it('should copy parent changes', inject(function() {
compile('<div><span my-component reference="{name: name}">');

$rootScope.name = 'a';
$rootScope.$apply();
expect(componentScope.reference).toEqual({name: 'a'});

$rootScope.name = 'b';
$rootScope.$apply();
expect(componentScope.reference).toEqual({name: 'b'});
}));

it('should not change the component when parent does not change', inject(function() {
compile('<div><span my-component reference="{name: name}">');

$rootScope.name = 'a';
$rootScope.$apply();
var lastComponentValue = componentScope.reference;
$rootScope.$apply();
expect(componentScope.reference).toBe(lastComponentValue);
}));

it('should complain when the component changes', inject(function() {
compile('<div><span my-component reference="{name: name}">');

$rootScope.name = 'a';
$rootScope.$apply();
componentScope.reference = {name: 'b'};
expect(function() {
$rootScope.$apply();
}).toThrowMinErr("$compile", "nonassign", "Expression '{name: name}' used with directive 'myComponent' is non-assignable!");

}));

it('should work for primitive literals', inject(function() {
test('1', 1);
test('null', null);
test('undefined', undefined);
test("'someString'", 'someString');


function test(literalString, literalValue) {
compile('<div><span my-component reference="'+literalString+'">');

$rootScope.$apply();
expect(componentScope.reference).toBe(literalValue);
dealoc(element);

}

}));

});

});


Expand Down

0 comments on commit 43072e3

Please sign in to comment.