From cefee8f0a3bba460a192ea6a32d60fec3d539a1c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 19 May 2014 23:22:32 +0100 Subject: [PATCH] fix($compile): fix nested isolated transclude directives Closes #1809 Closes #7499 --- src/ng/compile.js | 18 +++++++++--- test/ng/compileSpec.js | 66 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index abe856122e81..3b636ada8733 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -969,7 +969,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // or // - there is no boundTranscludeFn already and a transcludeFn was passed in if ( nodeLinkFn.transcludeOnThisElement || (!boundTranscludeFn && transcludeFn) ) { - boundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn); + boundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn, boundTranscludeFn); } nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn); @@ -981,8 +981,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } } - function createBoundTranscludeFn(scope, transcludeFn) { - return function boundTranscludeFn(transcludedScope, cloneFn, controllers) { + function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) { + + // If there is a previous boundTransclude function and it has a transclusionScope then + // use this instead of the current scope + scope = previousBoundTranscludeFn && previousBoundTranscludeFn.transclusionScope || scope; + + var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) { var scopeCreated = false; if (!transcludedScope) { @@ -997,6 +1002,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } return clone; }; + + // Store the transclusionScope for nested transclusions + boundTranscludeFn.transclusionScope = scope; + + return boundTranscludeFn; } /** @@ -1770,7 +1780,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { safeAddClass(jqLite(linkNode), oldClasses); } if (afterTemplateNodeLinkFn.transclude) { - childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude); + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); } else { childBoundTranscludeFn = boundTranscludeFn; } diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index df45976229fb..cf3c4324f56d 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -1567,6 +1567,72 @@ describe('$compile', function() { })); }); + describe('nested isolated scope transcludes', function() { + beforeEach(module(function($compileProvider) { + + $compileProvider.directive('trans', valueFn({ + restrict: 'E', + template: '
', + transclude: true + })); + + $compileProvider.directive('transAsync', valueFn({ + restrict: 'E', + templateUrl: 'transAsync', + transclude: true + })); + + $compileProvider.directive('iso', valueFn({ + restrict: 'E', + transclude: true, + template: '', + scope: {} + })); + $compileProvider.directive('isoAsync1', valueFn({ + restrict: 'E', + transclude: true, + template: '', + scope: {} + })); + $compileProvider.directive('isoAsync2', valueFn({ + restrict: 'E', + transclude: true, + templateUrl: 'isoAsync', + scope: {} + })); + })); + + beforeEach(inject(function($templateCache) { + $templateCache.put('transAsync', '
'); + $templateCache.put('isoAsync', ''); + })); + + + it('should pass the outer scope to the transclude on the isolated template sync-sync', inject(function($compile, $rootScope) { + + $rootScope.val = 'transcluded content'; + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(trim(element.text())).toEqual('transcluded content'); + })); + + it('should pass the outer scope to the transclude on the isolated template async-sync', inject(function($compile, $rootScope) { + + $rootScope.val = 'transcluded content'; + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(trim(element.text())).toEqual('transcluded content'); + })); + + it('should pass the outer scope to the transclude on the isolated template async-async', inject(function($compile, $rootScope) { + + $rootScope.val = 'transcluded content'; + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(trim(element.text())).toEqual('transcluded content'); + })); + + }); it("should fail if replacing and template doesn't have a single root element", function() {