Can you change templateUrl on the fly?
Solution 1
It is possible, but when your template to be loaded depends on some scope-data you can't use the directive's templateUrl
property anymore and you will be obliged to use lower-level API, namely $http
and $compile
.
Roughly what you need to do (only possible in the linking function) is to retrieve template's content using $http
(don't forget to involve $templateCache
!) and then compile template's content "manually".
It might sound like it is a lot of work but in practice it is rather straightforward. I would suggest having a look at the ngInclude
directive sources where this pattern is used.
Here is a skeleton of such a directive:
app.directive('boom', function($http, $templateCache, $compile, $parse) {
return {
restrict: 'E',
link: function(scope , iElement, iAttrs) {
var boom = $parse(iAttrs.data)(scope);
$http.get('myTemplate'+boom, {cache: $templateCache}).success(function(tplContent){
iElement.replaceWith($compile(tplContent)(scope));
});
}
}
});
assuming that it would be used as <boom data='name'></boom>
. Working plunk here: http://plnkr.co/edit/TunwvhPPS6MdiJxpNBg8?p=preview
Please note that I've changed attributes evaluation from {{name}}
to attributes parsing since probably a template should be determined only once, at the beginning.
Solution 2
This is a new feature in Angular versions 1.1.4+ I just found out if I use the current unstable (1.1.5) you can pass a function into the template url of a directive. The second parameter of the function is the value of the attribute directive as shown below.
Here is a link to the unpublished docs showing the official change.
To use partials/template1.html
as the template url from
Html:
<div sub_view="template1"></div>
Directive:
.directive('subView', [()->
restrict: 'A'
# this requires at least angular 1.1.4 (currently unstable)
templateUrl: (notsurewhatthisis, attr)->
"partials/#{attr.subView}.html"
])
Solution 3
I had similar problem
return {
restrict: 'AE',
templateUrl: function(elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
replace: true,
partnersSite.directive('navMenu', function () {
return {
restrict: 'AE',
templateUrl: function(elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
replace: true,
link: function (scope, elm, attrs) {
scope.hidden = true;
//other logics
}
};
});
<nav-menu scrolled="scrolled"></nav-menu>
Solution 4
This question will be fixed with ng-include as follow:
MyApp.directive('boom', function() {
return {
restrict: 'E',
transclude: true,
scope: 'isolate',
locals: { data: 'bind' },
templateUrl: '<div ng-include="templateUrl"></div>',
link: function (scope) {
function switchTemplate(temp) {
if (temp == 'x')
{ scope.templateUrl = 'XTemplate.html' }
else if (temp == 'y')
{ scope.templateUrl = 'YTemplate.html' }
}
}
}
});
Call the switchTemplate function with arbitrary temp parameter in the link function of directive.
Solution 5
I've changed the answer from pkozlowski.opensource a little.
From:
var boom = $parse(iAttrs.data)(scope);
To:
var boom = scope.data.myData
That worked for me and it's possible to use
<boom data="{{myData}}" />
in the directive.
Related videos on Youtube
iLemming
Updated on April 29, 2020Comments
-
iLemming about 4 years
Is it possible to change templateUrl on the fly by passing values in the directive's scope? I want to pass data to controller that will render the page based on the data that passed from the directive
something maybe that looks like that:
<div> <boom data="{{myData}}" /> </div> .directive('boom', function { return { restrict: 'E', transclude: true, scope: 'isolate', locals: { data: 'bind' }, templateUrl: "myTemplate({{boom}}})" // <- that of course won't work. } });
-
Iman Bahrampour about 6 years
-
-
iLemming over 11 yearsyeah, i'm trying to play with ngInclude, but I can't find how to get value of local variable. How to get
data
in my case? I'm trying attrs.data, but it returnsundefined
-
pkozlowski.opensource over 11 yearsProvided more info. I'm not sure if you really want to use interpolation of your attributes since it would mean that template can change dynamically as part of the $digest cycle. But if you really want to do so you would have to $observe attributes.
-
OpherV almost 11 yearsSolved my problem as well. Thanks!
-
EpiphanyMachine almost 11 yearsthe parameters are
(element, attributes)
-
HMR over 10 yearsI was using angular 1.0.8 and it may be worth mentioning that
$compile
fails when you didn't include jQuery before Angular.\ -
GFoley83 about 10 yearsExample forked from Plnkr above: http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn. Note this approach doesn't work with Angular 1.0.8 (as used above) as even though
iAttrs.data
has a value (which you can seen if you log theiAttrs
object), it'sundefined
when you try to access it. -
AlexK almost 10 yearsyou can't imagine how thankfull I am for this! I had a (similar) solution of my own, but combined with one of my directives, it just compiled two times... thank's so much!
-
andimeier almost 9 yearsIt seems to work also, if you use var boom = scope.data; instead of using $parse... Why should I resort to $parse instead?
-
Ceasar Bautista over 8 yearsThat's not the issue at heart. If you actually create a demo app similar to the OP's, you'll see that you can't simply pass the interpolated value to the directive's
templateURL
function. -
Joy George Kunjikkuru about 8 yearsDoes this help to have <nav-menu scrolled="{{scrolled}}"></nav-menu> ie my attribute value will change during runtime and needs to have different template url based on that.