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

Commit 74da034

Browse files
committedNov 10, 2015
fix($compile): fix scoping of transclusion directives inside replace directive
Closes #12975 Closes #12936 Closes #13244
1 parent 91ef94d commit 74da034

File tree

2 files changed

+82
-7
lines changed

2 files changed

+82
-7
lines changed
 

‎src/ng/compile.js

+26-7
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12931293
return function publicLinkFn(scope, cloneConnectFn, options) {
12941294
assertArg(scope, 'scope');
12951295

1296+
if (previousCompileContext && previousCompileContext.needsNewScope) {
1297+
// A parent directive did a replace and a directive on this element asked
1298+
// for transclusion, which caused us to lose a layer of element on which
1299+
// we could hold the new transclusion scope, so we will create it manually
1300+
// here.
1301+
scope = scope.$parent.$new();
1302+
}
1303+
12961304
options = options || {};
12971305
var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
12981306
transcludeControllers = options.transcludeControllers,
@@ -1768,7 +1776,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17681776
} else {
17691777
$template = jqLite(jqLiteClone(compileNode)).contents();
17701778
$compileNode.empty(); // clear contents
1771-
childTranscludeFn = compile($template, transcludeFn);
1779+
childTranscludeFn = compile($template, transcludeFn, undefined,
1780+
undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
17721781
}
17731782
}
17741783

@@ -1810,8 +1819,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18101819
var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
18111820
var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
18121821

1813-
if (newIsolateScopeDirective) {
1814-
markDirectivesAsIsolate(templateDirectives);
1822+
if (newIsolateScopeDirective || newScopeDirective) {
1823+
// The original directive caused the current element to be replaced but this element
1824+
// also needs to have a new scope, so we need to tell the template directives
1825+
// that they would need to get their scope from further up, if they require transclusion
1826+
markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
18151827
}
18161828
directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
18171829
mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
@@ -2096,10 +2108,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
20962108
}
20972109
}
20982110

2099-
function markDirectivesAsIsolate(directives) {
2100-
// mark all directives as needing isolate scope.
2111+
// Depending upon the context in which a directive finds itself it might need to have a new isolated
2112+
// or child scope created. For instance:
2113+
// * if the directive has been pulled into a template because another directive with a higher priority
2114+
// asked for element transclusion
2115+
// * if the directive itself asks for transclusion but it is at the root of a template and the original
2116+
// element was replaced. See https://github.com/angular/angular.js/issues/12936
2117+
function markDirectiveScope(directives, isolateScope, newScope) {
21012118
for (var j = 0, jj = directives.length; j < jj; j++) {
2102-
directives[j] = inherit(directives[j], {$$isolateScope: true});
2119+
directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
21032120
}
21042121
}
21052122

@@ -2246,7 +2263,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
22462263
var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
22472264

22482265
if (isObject(origAsyncDirective.scope)) {
2249-
markDirectivesAsIsolate(templateDirectives);
2266+
// the original directive that caused the template to be loaded async required
2267+
// an isolate scope
2268+
markDirectiveScope(templateDirectives, true);
22502269
}
22512270
directives = templateDirectives.concat(directives);
22522271
mergeTemplateAttributes(tAttrs, tempTemplateAttrs);

‎test/ng/compileSpec.js

+56
Original file line numberDiff line numberDiff line change
@@ -5636,6 +5636,62 @@ describe('$compile', function() {
56365636
});
56375637
});
56385638

5639+
//see issue https://github.com/angular/angular.js/issues/12936
5640+
it('should use the proper scope when it is on the root element of a replaced directive template', function() {
5641+
module(function() {
5642+
directive('isolate', valueFn({
5643+
scope: {},
5644+
replace: true,
5645+
template: '<div trans>{{x}}</div>',
5646+
link: function(scope, element, attr, ctrl) {
5647+
scope.x = 'iso';
5648+
}
5649+
}));
5650+
directive('trans', valueFn({
5651+
transclude: 'content',
5652+
link: function(scope, element, attr, ctrl, $transclude) {
5653+
$transclude(function(clone) {
5654+
element.append(clone);
5655+
});
5656+
}
5657+
}));
5658+
});
5659+
inject(function($rootScope, $compile) {
5660+
element = $compile('<isolate></isolate>')($rootScope);
5661+
$rootScope.x = 'root';
5662+
$rootScope.$apply();
5663+
expect(element.text()).toEqual('iso');
5664+
});
5665+
});
5666+
5667+
5668+
//see issue https://github.com/angular/angular.js/issues/12936
5669+
it('should use the proper scope when it is on the root element of a replaced directive template with child scope', function() {
5670+
module(function() {
5671+
directive('child', valueFn({
5672+
scope: true,
5673+
replace: true,
5674+
template: '<div trans>{{x}}</div>',
5675+
link: function(scope, element, attr, ctrl) {
5676+
scope.x = 'child';
5677+
}
5678+
}));
5679+
directive('trans', valueFn({
5680+
transclude: 'content',
5681+
link: function(scope, element, attr, ctrl, $transclude) {
5682+
$transclude(function(clone) {
5683+
element.append(clone);
5684+
});
5685+
}
5686+
}));
5687+
});
5688+
inject(function($rootScope, $compile) {
5689+
element = $compile('<child></child>')($rootScope);
5690+
$rootScope.x = 'root';
5691+
$rootScope.$apply();
5692+
expect(element.text()).toEqual('child');
5693+
});
5694+
});
56395695

56405696

56415697
it('should not leak if two "element" transclusions are on the same element (with debug info)', function() {

0 commit comments

Comments
 (0)
This repository has been archived.