aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ng/compile.js56
-rwxr-xr-xtest/ng/compileSpec.js87
-rw-r--r--xx0
3 files changed, 114 insertions, 29 deletions
diff --git a/src/ng/compile.js b/src/ng/compile.js
index d3ade6b8..adcbb6af 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -901,7 +901,7 @@ function $CompileProvider($provide) {
return linkFnFound ? compositeLinkFn : null;
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
- var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
+ var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
// copy nodeList so that linking doesn't break due to live list updates.
var stableNodeList = [];
@@ -913,11 +913,13 @@ function $CompileProvider($provide) {
node = stableNodeList[n];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
+ $node = jqLite(node);
if (nodeLinkFn) {
if (nodeLinkFn.scope) {
- childScope = scope.$new(isObject(nodeLinkFn.scope));
- jqLite(node).data('$scope', childScope);
+ childScope = scope.$new();
+ $node.data('$scope', childScope);
+ safeAddClass($node, 'ng-scope');
} else {
childScope = scope;
}
@@ -1155,10 +1157,8 @@ function $CompileProvider($provide) {
assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
$compileNode);
if (isObject(directiveValue)) {
- safeAddClass($compileNode, 'ng-isolate-scope');
newIsolateScopeDirective = directive;
}
- safeAddClass($compileNode, 'ng-scope');
}
}
@@ -1291,7 +1291,7 @@ function $CompileProvider($provide) {
}
- nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
+ nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
// might be normal or delayed nodeLinkFn depending on if templateUrl is present
@@ -1303,11 +1303,13 @@ function $CompileProvider($provide) {
if (pre) {
if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
pre.require = directive.require;
+ if (newIsolateScopeDirective === directive) pre.isolateScope = true;
preLinkFns.push(pre);
}
if (post) {
if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
post.require = directive.require;
+ if (newIsolateScopeDirective === directive) post.isolateScope = true;
postLinkFns.push(post);
}
}
@@ -1348,7 +1350,7 @@ function $CompileProvider($provide) {
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller;
+ var attrs, $element, i, ii, linkFn, controller, isolateScope;
if (compileNode === linkNode) {
attrs = templateAttrs;
@@ -1359,8 +1361,11 @@ function $CompileProvider($provide) {
if (newIsolateScopeDirective) {
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
+ var $linkNode = jqLite(linkNode);
- var parentScope = scope.$parent || scope;
+ isolateScope = scope.$new(true);
+ $linkNode.data('$isolateScope', isolateScope);
+ safeAddClass($linkNode, 'ng-isolate-scope');
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
var match = definition.match(LOCAL_REGEXP) || [],
@@ -1370,19 +1375,19 @@ function $CompileProvider($provide) {
lastValue,
parentGet, parentSet;
- scope.$$isolateBindings[scopeName] = mode + attrName;
+ isolateScope.$$isolateBindings[scopeName] = mode + attrName;
switch (mode) {
case '@':
attrs.$observe(attrName, function(value) {
- scope[scopeName] = value;
+ isolateScope[scopeName] = value;
});
- attrs.$$observers[attrName].$$scope = parentScope;
+ attrs.$$observers[attrName].$$scope = scope;
if( attrs[attrName] ) {
// If the attribute has been provided then we trigger an interpolation to ensure
// the value is there for use in the link fn
- scope[scopeName] = $interpolate(attrs[attrName])(parentScope);
+ isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
}
break;
@@ -1393,23 +1398,23 @@ function $CompileProvider($provide) {
parentGet = $parse(attrs[attrName]);
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
- lastValue = scope[scopeName] = parentGet(parentScope);
+ lastValue = isolateScope[scopeName] = parentGet(scope);
throw $compileMinErr('nonassign',
"Expression '{0}' used with directive '{1}' is non-assignable!",
attrs[attrName], newIsolateScopeDirective.name);
};
- lastValue = scope[scopeName] = parentGet(parentScope);
- scope.$watch(function parentValueWatch() {
- var parentValue = parentGet(parentScope);
+ lastValue = isolateScope[scopeName] = parentGet(scope);
+ isolateScope.$watch(function parentValueWatch() {
+ var parentValue = parentGet(scope);
- if (parentValue !== scope[scopeName]) {
+ if (parentValue !== isolateScope[scopeName]) {
// we are out of sync and need to copy
if (parentValue !== lastValue) {
// parent changed and it has precedence
- lastValue = scope[scopeName] = parentValue;
+ lastValue = isolateScope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
- parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
+ parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
}
}
return parentValue;
@@ -1418,8 +1423,8 @@ function $CompileProvider($provide) {
case '&':
parentGet = $parse(attrs[attrName]);
- scope[scopeName] = function(locals) {
- return parentGet(parentScope, locals);
+ isolateScope[scopeName] = function(locals) {
+ return parentGet(scope, locals);
};
break;
@@ -1435,7 +1440,7 @@ function $CompileProvider($provide) {
if (controllerDirectives) {
forEach(controllerDirectives, function(directive) {
var locals = {
- $scope: scope,
+ $scope: directive === newIsolateScopeDirective ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: boundTranscludeFn
@@ -1467,7 +1472,7 @@ function $CompileProvider($provide) {
for(i = 0, ii = preLinkFns.length; i < ii; i++) {
try {
linkFn = preLinkFns[i];
- linkFn(scope, $element, attrs,
+ linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.require, $element));
} catch (e) {
$exceptionHandler(e, startingTag($element));
@@ -1475,13 +1480,14 @@ function $CompileProvider($provide) {
}
// RECURSION
- childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
+ // TODO(vojta): only pass isolate if the isolate directive has template
+ childLinkFn && childLinkFn(isolateScope || scope, linkNode.childNodes, undefined, boundTranscludeFn);
// POSTLINKING
for(i = postLinkFns.length - 1; i >= 0; i--) {
try {
linkFn = postLinkFns[i];
- linkFn(scope, $element, attrs,
+ linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.require, $element));
} catch (e) {
$exceptionHandler(e, startingTag($element));
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index c6cba3a4..09048885 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -1375,7 +1375,7 @@ describe('$compile', function() {
return function (scope, element) {
iscope = scope;
log(scope.$id);
- expect(element.data('$scope')).toBe(scope);
+ expect(element.data('$isolateScope')).toBe(scope);
};
}
};
@@ -1416,7 +1416,7 @@ describe('$compile', function() {
return function (scope, element) {
iscope = scope;
log(scope.$id);
- expect(element.data('$scope')).toBe(scope);
+ expect(element.data('$isolateScope')).toBe(scope);
};
}
};
@@ -1535,7 +1535,7 @@ describe('$compile', function() {
expect(function(){
$compile('<div class="iscope-a; scope-b"></div>');
}).toThrowMinErr('$compile', 'multidir', 'Multiple directives [iscopeA, scopeB] asking for new/isolated scope on: ' +
- '<div class="iscope-a; scope-b ng-isolate-scope ng-scope">');
+ '<div class="iscope-a; scope-b">');
})
);
@@ -2085,7 +2085,7 @@ describe('$compile', function() {
describe('isolated locals', function() {
- var componentScope;
+ var componentScope, regularScope;
beforeEach(module(function() {
directive('myComponent', function() {
@@ -2112,6 +2112,23 @@ describe('$compile', function() {
scope: { attr: 'xxx' }
};
});
+ directive('storeScope', function() {
+ return {
+ link: function(scope) {
+ regularScope = scope;
+ }
+ }
+ });
+ }));
+
+ it('should give other directives the parent scope', inject(function($rootScope) {
+ compile('<div><input type="text" my-component store-scope ng-model="value"></div>');
+ $rootScope.$apply(function() {
+ $rootScope.value = 'from-parent';
+ });
+ expect(element.find('input').val()).toBe('from-parent');
+ expect(componentScope).not.toBe(regularScope);
+ expect(componentScope.$parent).toBe(regularScope)
}));
describe('attribute', function() {
@@ -2376,6 +2393,68 @@ describe('$compile', function() {
});
+ it('should require controller of an isolate directive from a non-isolate directive on the ' +
+ 'same element', function() {
+ var IsolateController = function() {};
+ var isolateDirControllerInNonIsolateDirective;
+
+ module(function() {
+ directive('isolate', function() {
+ return {
+ scope: {},
+ controller: IsolateController
+ };
+ });
+ directive('nonIsolate', function() {
+ return {
+ require: 'isolate',
+ link: function(_, __, ___, isolateDirController) {
+ isolateDirControllerInNonIsolateDirective = isolateDirController;
+ }
+ };
+ });
+ });
+
+ inject(function($compile, $rootScope) {
+ element = $compile('<div isolate non-isolate></div>')($rootScope);
+
+ expect(isolateDirControllerInNonIsolateDirective).toBeDefined();
+ expect(isolateDirControllerInNonIsolateDirective instanceof IsolateController).toBe(true);
+ });
+ });
+
+
+ it('should require controller of a non-isolate directive from an isolate directive on the ' +
+ 'same element', function() {
+ var NonIsolateController = function() {};
+ var nonIsolateDirControllerInIsolateDirective;
+
+ module(function() {
+ directive('isolate', function() {
+ return {
+ scope: {},
+ require: 'nonIsolate',
+ link: function(_, __, ___, nonIsolateDirController) {
+ nonIsolateDirControllerInIsolateDirective = nonIsolateDirController;
+ }
+ };
+ });
+ directive('nonIsolate', function() {
+ return {
+ controller: NonIsolateController
+ };
+ });
+ });
+
+ inject(function($compile, $rootScope) {
+ element = $compile('<div isolate non-isolate></div>')($rootScope);
+
+ expect(nonIsolateDirControllerInIsolateDirective).toBeDefined();
+ expect(nonIsolateDirControllerInIsolateDirective instanceof NonIsolateController).toBe(true);
+ });
+ });
+
+
it('should support controllerAs', function() {
module(function() {
directive('main', function() {
diff --git a/xx b/xx
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/xx