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

Commit 1fef5fe

Browse files
petebacondarwinvojtajina
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 bea77e4 commit 1fef5fe

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
@@ -936,7 +936,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
936936
return linkFnFound ? compositeLinkFn : null;
937937

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

941941
// copy nodeList so that linking doesn't break due to live list updates.
942942
var nodeListLength = nodeList.length,
@@ -958,14 +958,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
958958
} else {
959959
childScope = scope;
960960
}
961-
childTranscludeFn = nodeLinkFn.transclude;
962-
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
963-
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
964-
createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
965-
);
961+
962+
// We need to create a new boundTranscludeFn if
963+
// - a directive on this element wants to transclude
964+
// or
965+
// - there is no boundTranscludeFn already and a transcludeFn was passed in
966+
if ( nodeLinkFn.transcludeOnThisElement || (!boundTranscludeFn && transcludeFn) ) {
967+
childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn);
966968
} else {
967-
nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
969+
childBoundTranscludeFn = boundTranscludeFn;
968970
}
971+
972+
nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
973+
969974
} else if (childLinkFn) {
970975
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
971976
}
@@ -1341,7 +1346,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
13411346
}
13421347

13431348
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
1344-
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
1349+
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
1350+
nodeLinkFn.transclude = childTranscludeFn;
1351+
13451352
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
13461353

13471354
// 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
@@ -4206,6 +4206,115 @@ describe('$compile', function() {
42064206
});
42074207

42084208
});
4209+
4210+
4211+
describe('nested transcludes', function() {
4212+
4213+
beforeEach(module(function($compileProvider) {
4214+
4215+
$compileProvider.directive('noop', valueFn({}));
4216+
4217+
$compileProvider.directive('sync', valueFn({
4218+
template: '<div ng-transclude></div>',
4219+
transclude: true
4220+
}));
4221+
4222+
$compileProvider.directive('async', valueFn({
4223+
templateUrl: 'async',
4224+
transclude: true
4225+
}));
4226+
4227+
$compileProvider.directive('syncSync', valueFn({
4228+
template: '<div noop><div sync><div ng-transclude></div></div></div>',
4229+
transclude: true
4230+
}));
4231+
4232+
$compileProvider.directive('syncAsync', valueFn({
4233+
template: '<div noop><div async><div ng-transclude></div></div></div>',
4234+
transclude: true
4235+
}));
4236+
4237+
$compileProvider.directive('asyncSync', valueFn({
4238+
templateUrl: 'asyncSync',
4239+
transclude: true
4240+
}));
4241+
4242+
$compileProvider.directive('asyncAsync', valueFn({
4243+
templateUrl: 'asyncAsync',
4244+
transclude: true
4245+
}));
4246+
4247+
}));
4248+
4249+
beforeEach(inject(function($templateCache) {
4250+
$templateCache.put('async', '<div ng-transclude></div>');
4251+
$templateCache.put('asyncSync', '<div noop><div sync><div ng-transclude></div></div></div>');
4252+
$templateCache.put('asyncAsync', '<div noop><div async><div ng-transclude></div></div></div>');
4253+
}));
4254+
4255+
4256+
it('should allow nested transclude directives with sync template containing sync template', inject(function($compile, $rootScope) {
4257+
element = $compile('<div sync-sync>transcluded content</div>')($rootScope);
4258+
$rootScope.$digest();
4259+
expect(element.text()).toEqual('transcluded content');
4260+
}));
4261+
4262+
it('should allow nested transclude directives with sync template containing async template', inject(function($compile, $rootScope) {
4263+
element = $compile('<div sync-async>transcluded content</div>')($rootScope);
4264+
$rootScope.$digest();
4265+
expect(element.text()).toEqual('transcluded content');
4266+
}));
4267+
4268+
it('should allow nested transclude directives with async template containing sync template', inject(function($compile, $rootScope) {
4269+
element = $compile('<div async-sync>transcluded content</div>')($rootScope);
4270+
$rootScope.$digest();
4271+
expect(element.text()).toEqual('transcluded content');
4272+
}));
4273+
4274+
it('should allow nested transclude directives with async template containing asynch template', inject(function($compile, $rootScope) {
4275+
element = $compile('<div async-async>transcluded content</div>')($rootScope);
4276+
$rootScope.$digest();
4277+
expect(element.text()).toEqual('transcluded content');
4278+
}));
4279+
});
4280+
4281+
4282+
describe('multiple siblings receiving transclusion', function() {
4283+
4284+
it("should only receive transclude from parent", function() {
4285+
4286+
module(function($compileProvider) {
4287+
4288+
$compileProvider.directive('myExample', valueFn({
4289+
scope: {},
4290+
link: function link(scope, element, attrs) {
4291+
var foo = element[0].querySelector('.foo');
4292+
scope.children = angular.element(foo).children().length;
4293+
},
4294+
template: '<div>' +
4295+
'<div>myExample {{children}}!</div>' +
4296+
'<div ng-if="children">has children</div>' +
4297+
'<div class="foo" ng-transclude></div>' +
4298+
'</div>',
4299+
transclude: true
4300+
4301+
}));
4302+
4303+
});
4304+
4305+
inject(function($compile, $rootScope) {
4306+
var element = $compile('<div my-example></div>')($rootScope);
4307+
$rootScope.$digest();
4308+
expect(element.text()).toEqual('myExample 0!');
4309+
dealoc(element);
4310+
4311+
element = $compile('<div my-example><p></p></div>')($rootScope);
4312+
$rootScope.$digest();
4313+
expect(element.text()).toEqual('myExample 1!has children');
4314+
dealoc(element);
4315+
});
4316+
});
4317+
});
42094318
});
42104319

42114320

0 commit comments

Comments
 (0)