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

Commit

Permalink
fix($compile): pass transcludeFn down to nested transclude directives
Browse files Browse the repository at this point in the history
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.

Fixes #7240
Closes #7387
  • Loading branch information
vojtajina authored and IgorMinar committed May 16, 2014
1 parent d85c5e9 commit e466e98
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 9 deletions.
23 changes: 14 additions & 9 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return linkFnFound ? compositeLinkFn : null;

function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n;

// copy nodeList so that linking doesn't break due to live list updates.
var nodeListLength = nodeList.length,
Expand All @@ -963,14 +963,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
} else {
childScope = scope;
}
childTranscludeFn = nodeLinkFn.transclude;
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
);
} else {
nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);

// We need to create a new boundTranscludeFn if
// - a directive on this element wants to transclude
// or
// - there is no boundTranscludeFn already and a transcludeFn was passed in
if ( nodeLinkFn.transcludeOnThisElement || (!boundTranscludeFn && transcludeFn) ) {
boundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn);
}

nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);

} else if (childLinkFn) {
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
}
Expand Down Expand Up @@ -1346,7 +1349,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
nodeLinkFn.transclude = childTranscludeFn;

previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;

// might be normal or delayed nodeLinkFn depending on if templateUrl is present
Expand Down
72 changes: 72 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,78 @@ describe('$compile', function() {
));


describe('nested transcludes', function() {

beforeEach(module(function($compileProvider) {

$compileProvider.directive('noop', valueFn({}));

$compileProvider.directive('sync', valueFn({
template: '<div ng-transclude></div>',
transclude: true
}));

$compileProvider.directive('async', valueFn({
templateUrl: 'async',
transclude: true
}));

$compileProvider.directive('syncSync', valueFn({
template: '<div noop><div sync><div ng-transclude></div></div></div>',
transclude: true
}));

$compileProvider.directive('syncAsync', valueFn({
template: '<div noop><div async><div ng-transclude></div></div></div>',
transclude: true
}));

$compileProvider.directive('asyncSync', valueFn({
templateUrl: 'asyncSync',
transclude: true
}));

$compileProvider.directive('asyncAsync', valueFn({
templateUrl: 'asyncAsync',
transclude: true
}));

}));

beforeEach(inject(function($templateCache) {
$templateCache.put('async', '<div ng-transclude></div>');
$templateCache.put('asyncSync', '<div noop><div sync><div ng-transclude></div></div></div>');
$templateCache.put('asyncAsync', '<div noop><div async><div ng-transclude></div></div></div>');
}));


it('should allow nested transclude directives with sync template containing sync template', inject(function($compile, $rootScope) {
element = $compile('<div sync-sync>transcluded content</div>')($rootScope);
$rootScope.$digest();
expect(element.text().trim()).toEqual('transcluded content');
}));

it('should allow nested transclude directives with sync template containing async template', inject(function($compile, $rootScope) {
element = $compile('<div sync-async>transcluded content</div>')($rootScope);
$rootScope.$digest();
expect(element.text().trim()).toEqual('transcluded content');
}));

it('should allow nested transclude directives with async template containing sync template', inject(function($compile, $rootScope) {
element = $compile('<div async-sync>transcluded content</div>')($rootScope);
$rootScope.$digest();
expect(element.text().trim()).toEqual('transcluded content');
}));

it('should allow nested transclude directives with async template containing asynch template', inject(function($compile, $rootScope) {
element = $compile('<div async-async>transcluded content</div>')($rootScope);
$rootScope.$digest();
expect(element.text().trim()).toEqual('transcluded content');
}));
});



it("should fail if replacing and template doesn't have a single root element", function() {
module(function($exceptionHandlerProvider) {
$exceptionHandlerProvider.mode('log');
Expand Down

0 comments on commit e466e98

Please sign in to comment.