How to use defined text/ng-template in AngularJS directive

66,704

Solution 1

Looking at your directive i can suggest try ng-include. Where you want to do

//$compile(ComboboxDropdownTemplate) +

    '</div>'

change it to

<span ng-include='templateUrlPropertyOnScope'>

'</div>'

templateUrlPropertyOnScope property should point to a template either on server side or in script section created with type=text/ng-template.

Solution 2

HTML

<script type="text/ng-template" id="myDirectivesCustomTemplate.html">
    <ul>
        <li ng-repeat="value in values">
        <a ng-click="doSomething({id:value.id})">
                            {{value.name}}
        </a>
        </li>
    </ul>
</script>
<div ng-controller="MainCtrl">
     <div my-directive template="myDirectivesCustomTemplate.html" mydata="mydata" mycallback="doSomething(id)"></div>
</div>

JS

app.controller('MainCtrl',function($scope){
    $scope.mydata = [{id:1,name:'One'},{id:2,name:'Two'},{id:3,name:'Three'}];
    $scope.doSomething = function(id){
        alert(id); 
    }
});
app.directive('myDirective', function($templateCache,$compile) {
    return {
        restrict: 'A',
        scope:{
            template : "@",
            mydata : "=",
            mycallback:"&"
        },
        link: function(scope,element) {
            var template = $templateCache.get(scope.template);
            scope.values = scope.mydata;
            scope.doSomething = scope.mycallback;
            element.append($compile(template)(scope));
        }
    }
});

Solution 3

I know this is 4 years later but if anyone still has this question, perhaps this answer may also be found useful.

With a simple directive such as this:

<my-directive template="custom-template.html"></my-directive>

You can then refer to the template attribute in your directive, like this:

(function() {
  angular
    .module('app')
    .directive('myDirective', myDirective);

  function myDirective() {
    return {
      restrict: 'E',
      templateUrl: function(elem, attrs) {
        return attrs.template;
      }
    }
  }
}

Solution 4

you can use $http and $compile to achieve such a task.

app.directive('myDirective', function($http, $templateCache, $compile) {
  return {
    scope: {
      // reference to your data. 
      // Just use `data.values` or `data.whatever` in your template
      data: '=myDirectiveData'
    },
    link: function(scope, elm, attrs) {
      // Load the template via my-directive-custom-template attribute
      $http.get(attrs.myDirectiveCustomTemplate, {cache: $templateCache}).success(function(html) {
        // update the HTML
        elm.html(html);
        // compile the html against the scope
        return $compile(elm.contents())(scope);
      });
    }
  };
});

I hope it gives you a good start

Share:
66,704
Andresch Serj
Author by

Andresch Serj

Senior Full-Stack Developer that loves Angular/Typescript/NestJs and Bicycles. Loves Test Driven, Domain Driven, Component Driven and even Behaviour Driven. Loves T-Shaped Teams.

Updated on August 18, 2020

Comments

  • Andresch Serj
    Andresch Serj almost 4 years

    I try to write a very flexible directive. For doing so i want the user to define a template used in part of my return (as seen in the ui-bootstrap typeahead directive).

    So i define my template like this:

    <script type="text/ng-template" id="myDirectivesCustomTemplate.html">
      <ul>
        <li ng-repeat="value in values">
          <a ng-click="doSomething(value.id)">
            {{value.name}}
          </a>
        </li>
      </ul>
    </script>
    

    I set this template in my directive

    <div 
      my-directive 
      my-directive-custom-template="myDirectivesCustomTemplate.html" 
      my-directive-data="someScopeData">
    

    Now in my directive, how can i render the custom template and use it with the passed data? When i try to use it to return in template directly it throws a ReferenceError: $scope is not defined Error. If i call it without scope, it says ReferenceError: myDirectiveCustomTemplate is not defined Error.

    Where and how can i use my template if i do not just want to use it as a return directly?

    EDIT: let's say, this is my directive:

    (function() {
     'use strict';
     var Combobox = function() {
    
      var displayInputField     = elem.find('input.dropdown');
    
      scope.$watch(scope.nsdComboboxModel,function(newVal){
        /* search for newVal in given data object */
        scope.setDisplayInputValue(newVal);
      });
    
      scope.setDisplayInputValue = function(value)
      {
        displayInputField.val(value);
      };
    
      scope.elementSelected = function (item, model, label) {
        scope.ComboboxCallback(item);
        scope.setDisplayInputValue(label);
      };
     }
    
    
     return {
       restrict: 'A',
       transclude: true,
       scope: {
         Combobox:                  '@', /* used as HTML/CSS-id/name/path */
         ComboboxModel:             '=', /* the actual AngularJS model (ng-model) */
         ComboboxAutocompleteData:  '=', /* the data used for autoComplete (must be array of objects having id and value) */
         ComboboxDropdownData:      '=', /* data used by the dropdown template */
         ComboboxCallback:          '=', /* a callback function called with selected autocomplete data item on select */
         ComboboxLabel:             '@', /* label for the input field */
         ComboboxDropdownTemplate:  '@'  /* label for the input field */
     },
    
     template:
    
      '<section class="-combobox-directive container-fluid">' +
        '<label for="{{Combobox}}" ng-if="ComboboxTranslation" translate="{{ComboboxLabel}}"></label>' +
        '<div class="combobox input-group">' +
          '<input type="text" ' +
            'id="{{Combobox}}" ' +
            'autocomplete="off" ' +
            'ng-model="ComboboxDestinationDisplay" ' +
            'data-toggle="dropdown" ' +
            'typeahead="value as location.value for location in ComboboxAutocompleteData | filter:$viewValue" ' +
            'typeahead-editable="false" ' +
            'typeahead-on-select="elementSelected($item, $model, $label)" ' +
            'class="form-control dropdown">' + // dropdown-toggle
    
            '<span data-toggle="dropdown" class="input-group-addon dropdown-toggle">' +
              '<span class="glyphicon glyphicon-globe"></span>' +
            '</span>' +
    
            //$compile(ComboboxDropdownTemplate) +
    
        '</div>' +
      '</section>',
    
      link: link
     };
    };
    
    angular.module('vibe.directives').directive('nsdCombobox', [NsdCombobox]);
    })();