Skip to content

Commit 1de1f85

Browse files
committed
feat($compile): Allow using functions as templates in directives
Added dynamic template support in directives: - The call will pass the element and directive attributes as parameters - This allows generating templates on the fly - It also applies to templateUrl
1 parent 2508b47 commit 1de1f85

File tree

3 files changed

+111
-4
lines changed

3 files changed

+111
-4
lines changed

docs/content/guide/directive.ngdoc

+6-2
Original file line numberDiff line numberDiff line change
@@ -377,11 +377,15 @@ 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 the current elementa normalized list of attributes (see
382+
{@link guide/directive#Attributes Attributes}). The content returned by the call will be the
383+
template to be compiled.
381384

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

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

src/ng/compile.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ function $CompileProvider($provide) {
649649
if ((directiveValue = directive.template)) {
650650
assertNoDuplicate('template', templateDirective, directive, $compileNode);
651651
templateDirective = directive;
652+
if (isFunction(directive.template)) {
653+
directiveValue = directive.template($compileNode, templateAttrs);
654+
}
652655
directiveValue = denormalizeTemplate(directiveValue);
653656

654657
if (directive.replace) {
@@ -967,11 +970,19 @@ function $CompileProvider($provide) {
967970
// The fact that we have to copy and patch the directive seems wrong!
968971
derivedSyncDirective = extend({}, origAsyncDirective, {
969972
controller: null, templateUrl: null, transclude: null, scope: null
970-
});
973+
}),
974+
urlToLoad;
971975

972976
$compileNode.html('');
973977

974-
$http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
978+
if (isFunction(origAsyncDirective.templateUrl)) {
979+
urlToLoad = origAsyncDirective.templateUrl($compileNode, tAttrs);
980+
}
981+
else {
982+
urlToLoad = origAsyncDirective.templateUrl;
983+
}
984+
985+
$http.get(urlToLoad, {cache: $templateCache}).
975986
success(function(content) {
976987
var compileNode, tempTemplateAttrs, $template;
977988

test/ng/compileSpec.js

+92
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,50 @@ describe('$compile', function() {
625625
});
626626

627627

628+
describe('template function', function() {
629+
630+
beforeEach(module(function() {
631+
directive('replace', valueFn({
632+
restrict: 'CAM',
633+
replace: true,
634+
template: function(e,f) {
635+
return '<div class="log" style="width: 10px" high-log>Replace!</div>'
636+
},
637+
compile: function(element, attr) {
638+
attr.$set('compiled', 'COMPILED');
639+
expect(element).toBe(attr.$$element);
640+
}
641+
}));
642+
643+
directive('replaceattr', valueFn({
644+
restrict: 'CAM',
645+
replace: true,
646+
template: function(e,f) {
647+
expect(isElement(e)).toBeTruthy();
648+
return '<div class="log" style="width: 10px" high-log ' + f.myattr + '="123">Replace!</div>'
649+
},
650+
compile: function(element, attr) {
651+
expect(attr.dynamic).toBe('123');
652+
attr.$set('dynamic', '456');
653+
}
654+
}));
655+
}));
656+
657+
658+
it('should replace element with template returned by function', inject(function($compile, $rootScope) {
659+
element = $compile('<div><div replace>ignore</div><div>')($rootScope);
660+
expect(element.text()).toEqual('Replace!');
661+
expect(element.find('div').attr('compiled')).toEqual('COMPILED');
662+
}));
663+
664+
it('should pass element and attributes to template function', inject(function($compile, $rootScope) {
665+
element = $compile('<div><div replaceattr myattr="dynamic">ignore</div><div>')($rootScope);
666+
expect(element.text()).toEqual('Replace!');
667+
expect(element.find('div').attr('dynamic')).toEqual('456');
668+
}));
669+
});
670+
671+
628672
describe('templateUrl', function() {
629673

630674
beforeEach(module(
@@ -1155,6 +1199,54 @@ describe('$compile', function() {
11551199
});
11561200
});
11571201

1202+
describe('templateUrl function', function() {
1203+
1204+
beforeEach(module(
1205+
function() {
1206+
directive('hello', valueFn({
1207+
restrict: 'CAM', templateUrl: function(e,t) {
1208+
return 'hello.html';
1209+
},
1210+
transclude: true
1211+
}));
1212+
directive('cau', valueFn({
1213+
restrict: 'CAM', templateUrl: function(e,t) {
1214+
expect(isElement(e)).toBeTruthy();
1215+
return 'cau'+t.test+'.html';
1216+
}
1217+
}));
1218+
}
1219+
));
1220+
1221+
it('should compile, link and flush the template inline when using functions as templateUrl', inject(
1222+
function($compile, $templateCache, $rootScope) {
1223+
$templateCache.put('hello.html', '<span>Hello, {{name}}!</span>');
1224+
$rootScope.name = 'Elvis';
1225+
element = $compile('<div><b hello></b></div>')($rootScope);
1226+
1227+
$rootScope.$digest();
1228+
1229+
expect(sortedHtml(element)).
1230+
toEqual('<div><b><span>Hello, Elvis!</span></b></div>');
1231+
}
1232+
));
1233+
1234+
it('should pass element and attributes to the templateUrl function', inject(
1235+
function($compile, $templateCache, $rootScope) {
1236+
$templateCache.put('cau2.html', '<span>Hey, {{name}}!</span>');
1237+
$templateCache.put('cau3.html', '<span>Say: Hey, {{name}}!</span>');
1238+
$rootScope.name = 'me';
1239+
element = $compile('<div><b cau test="2"></b><b cau test="3"></b></div>')($rootScope);
1240+
1241+
$rootScope.$digest();
1242+
1243+
expect(sortedHtml(element)).
1244+
toEqual('<div><b test="2"><span>Hey, me!</span></b><b test="3">' +
1245+
'<span>Say: Hey, me!</span></b></div>');
1246+
}
1247+
));
1248+
});
1249+
11581250

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

0 commit comments

Comments
 (0)