Skip to content

Commit d40bc9f

Browse files
committed
feat($compile): Allow using functions as templates in directives
Added dynamic template support in directives: - The call will include the directive attributes common object as a parameter - This allows generating templates on the fly - It also applies to templateUrl
1 parent d30845a commit d40bc9f

File tree

3 files changed

+108
-4
lines changed

3 files changed

+108
-4
lines changed

docs/content/guide/directive.ngdoc

+5-2
Original file line numberDiff line numberDiff line change
@@ -377,11 +377,14 @@ compiler}. The attributes are:
377377

378378
* `template` - replace the current element with the contents of the HTML. The replacement process
379379
migrates all of the attributes / classes from the old element to the new one. See Creating
380-
Widgets section below for more information.
380+
Widgets section below for more information. If the template is a function, it will be called
381+
with a normalized list of attributes (see {@link guide/directive#Attributes Attributes}). The
382+
content returned by the call will be the template to be compiled.
381383

382384
* `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because
383385
the template loading is asynchronous the compilation/linking is suspended until the template
384-
is loaded.
386+
is loaded. You can also use a function that will return the URL to load. The call will include
387+
the normalized list of attributes as a single parameter.
385388

386389
* `replace` - if set to `true` then the template will replace the current element, rather than
387390
append the template to the element.

src/ng/compile.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@ function $CompileProvider($provide) {
595595
if ((directiveValue = directive.template)) {
596596
assertNoDuplicate('template', templateDirective, directive, $compileNode);
597597
templateDirective = directive;
598+
if (isFunction(directive.template)) {
599+
directiveValue = directive.template(templateAttrs);
600+
}
598601
directiveValue = denormalizeTemplate(directiveValue);
599602

600603
if (directive.replace) {
@@ -907,11 +910,19 @@ function $CompileProvider($provide) {
907910
// The fact that we have to copy and patch the directive seems wrong!
908911
derivedSyncDirective = extend({}, origAsyncDirective, {
909912
controller: null, templateUrl: null, transclude: null, scope: null
910-
});
913+
}),
914+
urlToLoad;
911915

912916
$compileNode.html('');
913917

914-
$http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
918+
if (isFunction(origAsyncDirective.templateUrl)) {
919+
urlToLoad = origAsyncDirective.templateUrl(tAttrs);
920+
}
921+
else {
922+
urlToLoad = origAsyncDirective.templateUrl;
923+
}
924+
925+
$http.get(urlToLoad, {cache: $templateCache}).
915926
success(function(content) {
916927
var compileNode, tempTemplateAttrs, $template;
917928

test/ng/compileSpec.js

+90
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,49 @@ describe('$compile', function() {
585585
});
586586

587587

588+
describe('template function', function() {
589+
590+
beforeEach(module(function() {
591+
directive('replace', valueFn({
592+
restrict: 'CAM',
593+
replace: true,
594+
template: function(f) {
595+
return '<div class="log" style="width: 10px" high-log>Replace!</div>'
596+
},
597+
compile: function(element, attr) {
598+
attr.$set('compiled', 'COMPILED');
599+
expect(element).toBe(attr.$$element);
600+
}
601+
}));
602+
603+
directive('replaceattr', valueFn({
604+
restrict: 'CAM',
605+
replace: true,
606+
template: function(f) {
607+
return '<div class="log" style="width: 10px" high-log ' + f.myattr + '="123">Replace!</div>'
608+
},
609+
compile: function(element, attr) {
610+
expect(attr.dynamic).toBe('123');
611+
attr.$set('dynamic', '456');
612+
}
613+
}));
614+
}));
615+
616+
617+
it('should replace element with template returned by function', inject(function($compile, $rootScope) {
618+
element = $compile('<div><div replace>ignore</div><div>')($rootScope);
619+
expect(element.text()).toEqual('Replace!');
620+
expect(element.find('div').attr('compiled')).toEqual('COMPILED');
621+
}));
622+
623+
it('should pass attributes to template function', inject(function($compile, $rootScope) {
624+
element = $compile('<div><div replaceattr myattr="dynamic">ignore</div><div>')($rootScope);
625+
expect(element.text()).toEqual('Replace!');
626+
expect(element.find('div').attr('dynamic')).toEqual('456');
627+
}));
628+
});
629+
630+
588631
describe('templateUrl', function() {
589632

590633
beforeEach(module(
@@ -1115,6 +1158,53 @@ describe('$compile', function() {
11151158
});
11161159
});
11171160

1161+
describe('templateUrl function', function() {
1162+
1163+
beforeEach(module(
1164+
function() {
1165+
directive('hello', valueFn({
1166+
restrict: 'CAM', templateUrl: function(t) {
1167+
return 'hello.html';
1168+
},
1169+
transclude: true
1170+
}));
1171+
directive('cau', valueFn({
1172+
restrict: 'CAM', templateUrl: function(t) {
1173+
return 'cau'+t.test+'.html';
1174+
}
1175+
}));
1176+
}
1177+
));
1178+
1179+
it('should compile, link and flush the template inline when using functions as templateUrl', inject(
1180+
function($compile, $templateCache, $rootScope) {
1181+
$templateCache.put('hello.html', '<span>Hello, {{name}}!</span>');
1182+
$rootScope.name = 'Elvis';
1183+
element = $compile('<div><b hello></b></div>')($rootScope);
1184+
1185+
$rootScope.$digest();
1186+
1187+
expect(sortedHtml(element)).
1188+
toEqual('<div><b><span>Hello, Elvis!</span></b></div>');
1189+
}
1190+
));
1191+
1192+
it('should pass attributes to the templateUrl function', inject(
1193+
function($compile, $templateCache, $rootScope) {
1194+
$templateCache.put('cau2.html', '<span>Hey, {{name}}!</span>');
1195+
$templateCache.put('cau3.html', '<span>Say: Hey, {{name}}!</span>');
1196+
$rootScope.name = 'me';
1197+
element = $compile('<div><b cau test="2"></b><b cau test="3"></b></div>')($rootScope);
1198+
1199+
$rootScope.$digest();
1200+
1201+
expect(sortedHtml(element)).
1202+
toEqual('<div><b test="2"><span>Hey, me!</span></b><b test="3">' +
1203+
'<span>Say: Hey, me!</span></b></div>');
1204+
}
1205+
));
1206+
});
1207+
11181208

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

0 commit comments

Comments
 (0)