From 19af0397456eb8fc06dea47145fdee0e38e62f81 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 23 May 2014 12:13:27 +0100 Subject: [PATCH] fix($compile): don't pass transclude to template of non-transclude directive If a directive provides a template but is not explicitly requesting transclusion then the compiler should not pass a transclusion function to the directives within the template. --- src/ng/compile.js | 25 +++++++++++++++++-------- test/ng/compileSpec.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index b7253679a08b..7ae720f4a2d4 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -924,7 +924,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { !childNodes.length) ? null : compileNodes(childNodes, - nodeLinkFn ? nodeLinkFn.transclude : transcludeFn); + nodeLinkFn ? ( + (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement) + && nodeLinkFn.transclude) : transcludeFn); linkFns.push(nodeLinkFn, childLinkFn); linkFnFound = linkFnFound || nodeLinkFn || childLinkFn; @@ -959,14 +961,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { childScope = scope; } - // We need to create a new boundTranscludeFn if - // - a directive on this element wants to transclude - // or - // - there is no parentBoundTranscludeFn already and a transcludeFn was passed in - if ( nodeLinkFn.transcludeOnThisElement || (!parentBoundTranscludeFn && transcludeFn) ) { - childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn, parentBoundTranscludeFn); - } else { + if ( nodeLinkFn.transcludeOnThisElement ) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn); + + } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) { childBoundTranscludeFn = parentBoundTranscludeFn; + + } else if (!parentBoundTranscludeFn && transcludeFn) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn); + + } else { + childBoundTranscludeFn = null; } nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn); @@ -1181,6 +1186,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { templateDirective = previousCompileContext.templateDirective, nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, hasTranscludeDirective = false, + hasTemplate = false, hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective, $compileNode = templateAttrs.$$element = jqLite(compileNode), directive, @@ -1271,6 +1277,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (directive.template) { + hasTemplate = true; assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; @@ -1320,6 +1327,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (directive.templateUrl) { + hasTemplate = true; assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; @@ -1357,6 +1365,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective; + nodeLinkFn.templateOnThisElement = hasTemplate; nodeLinkFn.transclude = childTranscludeFn; previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index b7d2e7aaf932..cce526d17363 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -3988,6 +3988,39 @@ describe('$compile', function() { }); + it('should not pass transclusion into a template directive when the directive didn\'t request transclusion', function() { + + module(function($compileProvider) { + + $compileProvider.directive('transFoo', valueFn({ + template: '
' + + '
' + + '
this one should get replaced with content
' + + '
' + + '
', + transclude: true + + })); + + $compileProvider.directive('noTransBar', valueFn({ + template: '
' + + // This ng-transclude is invalid. It should throw an error. + '
' + + '
', + transclude: false + + })); + }); + + inject(function($compile, $rootScope) { + expect(function() { + $compile('
content
')($rootScope); + }).toThrowMinErr('ngTransclude', 'orphan', + 'Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element:
'); + }); + }); + + it('should make the result of a transclusion available to the parent directive in post-linking phase' + '(template)', function() { module(function() {