Can you change templateUrl on the fly?

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.
        }
    });

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.


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"
])

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>