Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
feat($compile): support for dynamic template generation
Browse files Browse the repository at this point in the history
`template` and `templateUrl` properties can now be optionally defined
via a function. This allows templates to be dynamically generated on
the fly.
  • Loading branch information
lrlopez authored and IgorMinar committed Feb 28, 2013
1 parent 5e18a15 commit eb53423
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
8 changes: 8 additions & 0 deletions docs/content/guide/directive.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
14 changes: 11 additions & 3 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down
57 changes: 57 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 '<div id="templateContent">template content</div>';
},
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('<div my-directive="some value">original content<div>')($rootScope);
expect(element.text()).toEqual('template content');
}));
});


describe('templateUrl', function() {

beforeEach(module(
Expand Down Expand Up @@ -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', '<div id="templateContent">template content</span>');
element = $compile('<div my-directive="some value">original content<div>')($rootScope);
expect(element.text()).toEqual('');

$rootScope.$digest();

expect(element.text()).toEqual('template content');
}));
});


describe('scope', function() {
var iscope;

Expand Down

2 comments on commit eb53423

@coli
Copy link

@coli coli commented on eb53423 Feb 28, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! No access to the $scope but you don't have it at compile time.

@joshkurz
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Please sign in to comment.