From eb53423a41136fcda0c5e711f2d104952080354b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Ram=C3=B3n=20L=C3=B3pez?= Date: Thu, 21 Feb 2013 21:56:40 +0100 Subject: [PATCH] feat($compile): support for dynamic template generation `template` and `templateUrl` properties can now be optionally defined via a function. This allows templates to be dynamically generated on the fly. --- docs/content/guide/directive.ngdoc | 8 +++++ src/ng/compile.js | 14 ++++++-- test/ng/compileSpec.js | 57 ++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/docs/content/guide/directive.ngdoc b/docs/content/guide/directive.ngdoc index 59b89b403383..2253ea3024a3 100644 --- a/docs/content/guide/directive.ngdoc +++ b/docs/content/guide/directive.ngdoc @@ -406,10 +406,18 @@ compiler}. The attributes are: migrates all of the attributes / classes from the old element to the new one. See the {@link guide/directive#Components Creating Components} section below for more information. + You can specify `template` as a string representing the template or as a function which takes + two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns + a string value representing the template. + * `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because the template loading is asynchronous the compilation/linking is suspended until the template is loaded. + You can specify `templateUrl` as a string representing the URL or as a function which takes two + arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns + a string value representing the url. + * `replace` - if set to `true` then the template will replace the current element, rather than append the template to the element. diff --git a/src/ng/compile.js b/src/ng/compile.js index 3746bb66821d..c04d38716ded 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -652,9 +652,14 @@ function $CompileProvider($provide) { } } - if ((directiveValue = directive.template)) { + if (directive.template) { assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; + + directiveValue = (isFunction(directive.template)) + ? directive.template($compileNode, templateAttrs) + : directive.template; + directiveValue = denormalizeTemplate(directiveValue); if (directive.replace) { @@ -977,11 +982,14 @@ function $CompileProvider($provide) { // The fact that we have to copy and patch the directive seems wrong! derivedSyncDirective = extend({}, origAsyncDirective, { controller: null, templateUrl: null, transclude: null, scope: null - }); + }), + templateUrl = (isFunction(origAsyncDirective.templateUrl)) + ? origAsyncDirective.templateUrl($compileNode, tAttrs) + : origAsyncDirective.templateUrl; $compileNode.html(''); - $http.get(origAsyncDirective.templateUrl, {cache: $templateCache}). + $http.get(templateUrl, {cache: $templateCache}). success(function(content) { var compileNode, tempTemplateAttrs, $template; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 6f56c6e68b19..f81199cb92aa 100644 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -647,6 +647,32 @@ describe('$compile', function() { }); + describe('template as function', function() { + + beforeEach(module(function() { + directive('myDirective', valueFn({ + replace: true, + template: function($element, $attrs) { + expect($element.text()).toBe('original content'); + expect($attrs.myDirective).toBe('some value'); + return '
template content
'; + }, + compile: function($element, $attrs) { + expect($element.text()).toBe('template content'); + expect($attrs.id).toBe('templateContent'); + } + })); + })); + + + it('should evaluate `template` when defined as fn and use returned string as template', inject( + function($compile, $rootScope) { + element = $compile('
original content
')($rootScope); + expect(element.text()).toEqual('template content'); + })); + }); + + describe('templateUrl', function() { beforeEach(module( @@ -1215,6 +1241,37 @@ describe('$compile', function() { }); + describe('template as function', function() { + + beforeEach(module(function() { + directive('myDirective', valueFn({ + replace: true, + templateUrl: function($element, $attrs) { + expect($element.text()).toBe('original content'); + expect($attrs.myDirective).toBe('some value'); + return 'my-directive.html'; + }, + compile: function($element, $attrs) { + expect($element.text()).toBe('template content'); + expect($attrs.id).toBe('templateContent'); + } + })); + })); + + + it('should evaluate `templateUrl` when defined as fn and use returned value as url', inject( + function($compile, $rootScope, $templateCache) { + $templateCache.put('my-directive.html', '
template content'); + element = $compile('
original content
')($rootScope); + expect(element.text()).toEqual(''); + + $rootScope.$digest(); + + expect(element.text()).toEqual('template content'); + })); + }); + + describe('scope', function() { var iscope;