From d414b787173643362c0c513a1929d8e715ca340e Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 23 May 2014 12:11:28 +0100 Subject: [PATCH] fix($compile): fix nested isolated transclude directives Closes #1809 Closes #7499 --- src/ng/compile.js | 18 +++++++++--- test/ng/compileSpec.js | 67 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 32f88a41bc8a..6ad1899f5f1d 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -964,7 +964,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // or // - there is no parentBoundTranscludeFn already and a transcludeFn was passed in if ( nodeLinkFn.transcludeOnThisElement || (!parentBoundTranscludeFn && transcludeFn) ) { - childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn); + childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude || transcludeFn, parentBoundTranscludeFn); } else { childBoundTranscludeFn = parentBoundTranscludeFn; } @@ -978,8 +978,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) { @@ -994,6 +999,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } return clone; }; + + // Store the transclusionScope for nested transclusions + boundTranscludeFn.transclusionScope = scope; + + return boundTranscludeFn; } /** @@ -1768,7 +1778,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 4d1610bcd714..b7d2e7aaf932 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -4279,6 +4279,73 @@ 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(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(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(element.text()).toEqual('transcluded content'); + })); + + }); + describe('multiple siblings receiving transclusion', function() { it("should only receive transclude from parent", function() {