49

I've got a recursive Angular directive that uses a template variable and gets compiled in the link function.

Problem is, that my template has gotten really long and out of control and I want to externalize it in an external HTML file (it would also make it easier for example to auto-indent).

How can you load an external template into a directive that can be used inside the $compile?

I've seen templateURL, but that doesn't let me name the variable and pass it to the $compile function.

var template = 
           "<p>My template</p>"+
           "<this-directive val='pass-value'></this-directive>";

return {
     scope: {
     ...
     },
     ...
     link: function(scope, element){
            element.html(template);
            $compile(element.contents())(scope);
        }
}

and

CodyBugstein
  • 21,984
  • 61
  • 207
  • 363

2 Answers2

109

You can use the $templateRequest service to get the template. This is a convenience service that also caches the template in $templateCache, so that only a single request to template.html is made.

As an illustration (and without going into the issue of recursive directives), this is used like so:

link: function(scope, element){
   $templateRequest("template.html").then(function(html){
      var template = angular.element(html);
      element.append(template);
      $compile(template)(scope);
   });
};

plunker (check the network tab to see a single network request)

New Dev
  • 48,427
  • 12
  • 87
  • 129
  • 11
    This is awesome! You are my hero! Can I buy you a coffee? – CodyBugstein Mar 04 '15 at 22:24
  • I'm curious, is it possible to use html binding (ng-bind-html) inside the "template.html" in your illustration? I can't make it work. – zhekaus Mar 13 '16 at 20:32
  • 1
    @zhekaus, yes, but it you still need to use the usual `ngSanitize`/`$sanitize` or otherwise use `$sce.trustAsHtml` – New Dev Mar 15 '16 at 12:21
  • Do you know why this appears to uncompile whenever it is converted to a string or console logged? – A Star Sep 02 '16 at 11:39
  • Just curious is there is a way to maintain two way binding for the template.html – AshD Apr 24 '18 at 07:14
3

I prefer to use $http to load template if its size is bigger:-

$http.get('mytemp.html').then(function(response) {
            element.html(response.data);
            $compile(element.contents())(scope);
            });
Asqan
  • 4,319
  • 11
  • 61
  • 100
squiroid
  • 13,809
  • 6
  • 47
  • 67
  • 1
    You should cache the templates that you load, like this `$http.get('mytem.html', {cache: $templateCache}).then(function(response) { element.html(response.data); $compile(element.contents())(scope); })` – Leonardo Jun 05 '15 at 12:50
  • 1
    There is a missing parenthesis in the code but I can't edit because it's less than 6 chars :) – Leonardo Jun 05 '15 at 12:52
  • 5
    _"The $templateRequest service runs security checks then downloads the provided template using $http and, upon success, stores the contents inside of $templateCache."_ [AngularJS](https://docs.angularjs.org/api/ng/service/$templateRequest) So `$templateCache` uses `$http` performing additional operations in one line. The only difference I see is that the template is not put into `$templateCache`, was it the purpose of your code? – felix at housecat Nov 16 '15 at 15:16