16

So as of Angular 1.1.4, you can have a dynamic template url. From here,

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.

How can I utilize this to generate a dynamic template based on, say, an attribute on my directive? Obviously this doesn't work, since tAttrs.templateType is simply the string "templateType"

templateUrl: function (tElement, tAttrs) {
  if (tAttrs.templateType == 'search') {
    return '/b/js/vendor/angular-ui/template/typeahead/typeahead.html'
  } else {
    return '/b/js/vendor/angular-ui/template/typeahead/typeahead2.html'
  }
}

Given that I don't have access to the scope, how do I manage this?

1
  • As of Angular 1.2.17 (and possibly earlier), your original idea seems to work. Commented Jun 12, 2014 at 19:23

4 Answers 4

29

The following is also possible for creating dynamic templates in AngularJS: In your directive use:

template : '<div ng-include="getTemplateUrl()"></div>'

Now your controller may decide which template to use:

$scope.getTemplateUrl = function() {
  return '/template/angular/search';
};

Because you have access to your scope parameters, you could also do:

$scope.getTemplateUrl = function() {
  return '/template/angular/search/' + $scope.query;
};

So your server could create a dynamic template for you.

Sign up to request clarification or add additional context in comments.

2 Comments

While this is an interesting, however, it seems to go against the grain of angular design, because it introduces a dependency between the directive and the controller which will dilute the encapsulation and standalone capability of the directive.
You could instead declare/assign the dynamic function inside of a link: property in the directive, since link can take a callback function(scope, element, attrs) that provides access to scope. This improves its ability to stand alone.
4
templateUrl: function (elem, attrs) {
return attrs["template"] == "table" ?
"tableTemplate.html" : "itemTemplate.html";
}

1 Comment

While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
1

So the issue was with how I hacked the typeahead directive ... I was setting a scope variable on the typeahead, to be evaluated on the typeaheadPopup directive. Instead, I just passed the templateType attr directly as string & evaluated that. E.g.

var popUpEl = angular.element(
  "<typeahead-popup " +
    "matches='matches' " +
    "active='activeIdx' " +
    "select='select(activeIdx)' " +
    "template-type='" + attrs.templateType + "'" +
    "query='query' " +
    "position='position'>" +
  "</typeahead-popup>");

Instead of "template-type='templateType'"

Comments

1

Ran into a similar issue when creating a file upload fallback for browsers that don't support the File API (< IE10). Key difference is I needed the page to intelligently decide which template to display without the benefit of an attribute value to switch on.

I ended up using the constant provider for my directive. Constants basically set up default parameters that can be injected anywhere in your directive. I simply let the constant call a function to determine browser support, then reference that value when I need to determine which template to pull. This is nice since 1) there's no attribute to reference and 2) it's available during the pre-link phase when you don't have access to the controller.

(function () {
  var myDir = angular.module('myDir', []);
  myDir.constant('myDirConfig', {
      hasFileSupport: fileApiIsSupported()
    });

  myDir.directive('myDir', ['myDirConfig', function (myDirConfig) {
      return {
          templateUrl: function () {
              if (myDirConfig.hasFileSupport) {
                  return 'pathToTemplate/html5.html';
              } else {
                  return 'pathToTemplate/fallback.html';
              }
          }
      };
  }];

  function fileApiIsSupported() { return (...); }
})();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.