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

Commit 8df5f32

Browse files
petebacondarwincaitp
authored andcommitted
fix($compile): pass transcludeFn down to nested transclude directives
If you have two directives that both expect to receive transcluded content the outer directive works but the inner directive never receives a transclusion function. This only failed if the first transclude directive was not the first directive found in compilation. Handles the regression identified in e994259 Fixes #7240 Closes #7387
1 parent 14e797c commit 8df5f32

File tree

2 files changed

+124
-8
lines changed

2 files changed

+124
-8
lines changed

src/ng/compile.js

+15-8
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
919919
return linkFnFound ? compositeLinkFn : null;
920920

921921
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
922-
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
922+
var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
923923

924924
// copy nodeList so that linking doesn't break due to live list updates.
925925
var nodeListLength = nodeList.length,
@@ -941,14 +941,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
941941
} else {
942942
childScope = scope;
943943
}
944-
childTranscludeFn = nodeLinkFn.transclude;
945-
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
946-
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
947-
createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
948-
);
944+
945+
// We need to create a new boundTranscludeFn if
946+
// - a directive on this element wants to transclude
947+
// or
948+
// - there is no boundTranscludeFn already and a transcludeFn was passed in
949+
if ( nodeLinkFn.transcludeOnThisElement || (!boundTranscludeFn && transcludeFn) ) {
950+
childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn);
949951
} else {
950-
nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
952+
childBoundTranscludeFn = boundTranscludeFn;
951953
}
954+
955+
nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
956+
952957
} else if (childLinkFn) {
953958
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
954959
}
@@ -1324,7 +1329,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
13241329
}
13251330

13261331
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
1327-
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
1332+
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
1333+
nodeLinkFn.transclude = childTranscludeFn;
1334+
13281335
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
13291336

13301337
// might be normal or delayed nodeLinkFn depending on if templateUrl is present

test/ng/compileSpec.js

+109
Original file line numberDiff line numberDiff line change
@@ -3982,6 +3982,115 @@ describe('$compile', function() {
39823982
});
39833983

39843984
});
3985+
3986+
3987+
describe('nested transcludes', function() {
3988+
3989+
beforeEach(module(function($compileProvider) {
3990+
3991+
$compileProvider.directive('noop', valueFn({}));
3992+
3993+
$compileProvider.directive('sync', valueFn({
3994+
template: '<div ng-transclude></div>',
3995+
transclude: true
3996+
}));
3997+
3998+
$compileProvider.directive('async', valueFn({
3999+
templateUrl: 'async',
4000+
transclude: true
4001+
}));
4002+
4003+
$compileProvider.directive('syncSync', valueFn({
4004+
template: '<div noop><div sync><div ng-transclude></div></div></div>',
4005+
transclude: true
4006+
}));
4007+
4008+
$compileProvider.directive('syncAsync', valueFn({
4009+
template: '<div noop><div async><div ng-transclude></div></div></div>',
4010+
transclude: true
4011+
}));
4012+
4013+
$compileProvider.directive('asyncSync', valueFn({
4014+
templateUrl: 'asyncSync',
4015+
transclude: true
4016+
}));
4017+
4018+
$compileProvider.directive('asyncAsync', valueFn({
4019+
templateUrl: 'asyncAsync',
4020+
transclude: true
4021+
}));
4022+
4023+
}));
4024+
4025+
beforeEach(inject(function($templateCache) {
4026+
$templateCache.put('async', '<div ng-transclude></div>');
4027+
$templateCache.put('asyncSync', '<div noop><div sync><div ng-transclude></div></div></div>');
4028+
$templateCache.put('asyncAsync', '<div noop><div async><div ng-transclude></div></div></div>');
4029+
}));
4030+
4031+
4032+
it('should allow nested transclude directives with sync template containing sync template', inject(function($compile, $rootScope) {
4033+
element = $compile('<div sync-sync>transcluded content</div>')($rootScope);
4034+
$rootScope.$digest();
4035+
expect(element.text()).toEqual('transcluded content');
4036+
}));
4037+
4038+
it('should allow nested transclude directives with sync template containing async template', inject(function($compile, $rootScope) {
4039+
element = $compile('<div sync-async>transcluded content</div>')($rootScope);
4040+
$rootScope.$digest();
4041+
expect(element.text()).toEqual('transcluded content');
4042+
}));
4043+
4044+
it('should allow nested transclude directives with async template containing sync template', inject(function($compile, $rootScope) {
4045+
element = $compile('<div async-sync>transcluded content</div>')($rootScope);
4046+
$rootScope.$digest();
4047+
expect(element.text()).toEqual('transcluded content');
4048+
}));
4049+
4050+
it('should allow nested transclude directives with async template containing asynch template', inject(function($compile, $rootScope) {
4051+
element = $compile('<div async-async>transcluded content</div>')($rootScope);
4052+
$rootScope.$digest();
4053+
expect(element.text()).toEqual('transcluded content');
4054+
}));
4055+
});
4056+
4057+
4058+
describe('multiple siblings receiving transclusion', function() {
4059+
4060+
it("should only receive transclude from parent", function() {
4061+
4062+
module(function($compileProvider) {
4063+
4064+
$compileProvider.directive('myExample', valueFn({
4065+
scope: {},
4066+
link: function link(scope, element, attrs) {
4067+
var foo = element[0].querySelector('.foo');
4068+
scope.children = angular.element(foo).children().length;
4069+
},
4070+
template: '<div>' +
4071+
'<div>myExample {{children}}!</div>' +
4072+
'<div ng-if="children">has children</div>' +
4073+
'<div class="foo" ng-transclude></div>' +
4074+
'</div>',
4075+
transclude: true
4076+
4077+
}));
4078+
4079+
});
4080+
4081+
inject(function($compile, $rootScope) {
4082+
var element = $compile('<div my-example></div>')($rootScope);
4083+
$rootScope.$digest();
4084+
expect(element.text()).toEqual('myExample 0!');
4085+
dealoc(element);
4086+
4087+
element = $compile('<div my-example><p></p></div>')($rootScope);
4088+
$rootScope.$digest();
4089+
expect(element.text()).toEqual('myExample 1!has children');
4090+
dealoc(element);
4091+
});
4092+
});
4093+
});
39854094
});
39864095

39874096

0 commit comments

Comments
 (0)