From 0c14f2f9a1dee88e2c8bc49f969cde89556a6721 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Mon, 21 Oct 2013 17:38:43 -0700 Subject: [PATCH] fix($compile): instantiate controlers when re-entering compilation When we re-enter compilation either due to async directive templates or element transclude directive we need to keep track of controllers to instantiate during linking. This piece of info was missing when re-entering compilation and that's what this commit fixes. I also reordered the properties in the previousCompileContext object. Closes #4434 --- src/ng/compile.js | 18 +++++++------- test/ng/compileSpec.js | 54 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 2ff9144bc232..e6300f150526 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1117,16 +1117,16 @@ function $CompileProvider($provide) { var terminalPriority = -Number.MAX_VALUE, newScopeDirective, + controllerDirectives = previousCompileContext.controllerDirectives, newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, templateDirective = previousCompileContext.templateDirective, + transcludeDirective = previousCompileContext.transcludeDirective, $compileNode = templateAttrs.$$element = jqLite(compileNode), directive, directiveName, $template, - transcludeDirective = previousCompileContext.transcludeDirective, replaceDirective = originalReplaceDirective, childTranscludeFn = transcludeFn, - controllerDirectives, linkFn, directiveValue; @@ -1191,9 +1191,10 @@ function $CompileProvider($provide) { childTranscludeFn = compile($template, transcludeFn, terminalPriority, replaceDirective && replaceDirective.name, { + controllerDirectives: controllerDirectives, newIsolateScopeDirective: newIsolateScopeDirective, - transcludeDirective: transcludeDirective, - templateDirective: templateDirective + templateDirective: templateDirective, + transcludeDirective: transcludeDirective }); } else { $template = jqLite(jqLiteClone(compileNode)).contents(); @@ -1259,9 +1260,10 @@ function $CompileProvider($provide) { nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, { + controllerDirectives: controllerDirectives, newIsolateScopeDirective: newIsolateScopeDirective, - transcludeDirective: transcludeDirective, - templateDirective: templateDirective + templateDirective: templateDirective, + transcludeDirective: transcludeDirective }); ii = directives.length; } else if (directive.compile) { @@ -1415,7 +1417,7 @@ function $CompileProvider($provide) { return parentGet(parentScope, locals); }; break; - + default: throw $compileMinErr('iscp', "Invalid isolate scope definition for directive '{0}'." + @@ -1819,7 +1821,7 @@ function directiveNormalize(name) { /** * @ngdoc object * @name ng.$compile.directive.Attributes - * + * * @description * A shared object between directive compile / linking functions which contains normalized DOM * element attributes. The the values reflect current binding state `{{ }}`. The normalization is diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 9a69824aaca3..0bba6b3737ab 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -2282,6 +2282,60 @@ describe('$compile', function() { }); + it('should get required controller via linkingFn (template)', function() { + module(function() { + directive('dirA', function() { + return { + controller: function() { + this.name = 'dirA'; + } + }; + }); + directive('dirB', function(log) { + return { + require: 'dirA', + template: '

dirB

', + link: function(scope, element, attrs, dirAController) { + log('dirAController.name: ' + dirAController.name); + } + }; + }); + }); + inject(function(log, $compile, $rootScope) { + element = $compile('
')($rootScope); + expect(log).toEqual('dirAController.name: dirA'); + }); + }); + + + it('should get required controller via linkingFn (templateUrl)', function() { + module(function() { + directive('dirA', function() { + return { + controller: function() { + this.name = 'dirA'; + } + }; + }); + directive('dirB', function(log) { + return { + require: 'dirA', + templateUrl: 'dirB.html', + link: function(scope, element, attrs, dirAController) { + log('dirAController.name: ' + dirAController.name); + } + }; + }); + }); + inject(function(log, $compile, $rootScope, $templateCache) { + $templateCache.put('dirB.html', '

dirB

'); + element = $compile('
')($rootScope); + $rootScope.$digest(); + expect(log).toEqual('dirAController.name: dirA'); + }); + }); + + it('should support controllerAs', function() { module(function() { directive('main', function() {