Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a directive with a dynamic template in AngularJS?

How can I create a directive with a dynamic template?

'use strict';

app.directive('ngFormField', function($compile) {
return {
    transclude: true,
    scope: {
        label: '@'
    },
    template: '<label for="user_email">{{label}}</label>',
    // append
    replace: true,
    // attribute restriction
    restrict: 'E',
    // linking method
    link: function($scope, element, attrs) {
        switch (attrs['type']) {
            case "text":
                // append input field to "template"
            case "select":
                // append select dropdown to "template"
        }
    }
  }
});
<ng-form-field label="First Name" type="text"></ng-form-field>

This is what I have right now, and it is displaying the label correctly. However, I'm not sure on how to append additional HTML to the template. Or combining 2 templates into 1.

like image 413
teepusink Avatar asked Feb 13 '13 20:02

teepusink


People also ask

Can we create custom directive in AngularJS?

AngularJS allows you to create custom directives with which it becomes easier to encapsulate and simplify DOM manipulation in AngularJS. These directives extend the HTML functionality.

How many types of directives are there in AngularJS?

There are two types of AngularJs directives: Built-in directive.

What are templates in AngularJS?

In AngularJS, templates are written with HTML that contains AngularJS-specific elements and attributes. AngularJS combines the template with information from the model and controller to render the dynamic view that a user sees in the browser.


3 Answers

i've used the $templateCache to accomplish something similar. i put several ng-templates in a single html file, which i reference using the directive's templateUrl. that ensures the html is available to the template cache. then i can simply select by id to get the ng-template i want.

template.html:

<script type="text/ng-template" id=“foo”> foo </script>  <script type="text/ng-template" id=“bar”> bar </script> 

directive:

myapp.directive(‘foobardirective’, ['$compile', '$templateCache', function ($compile, $templateCache) {      var getTemplate = function(data) {         // use data to determine which template to use         var templateid = 'foo';         var template = $templateCache.get(templateid);         return template;     }      return {         templateUrl: 'views/partials/template.html',         scope: {data: '='},         restrict: 'E',         link: function(scope, element) {             var template = getTemplate(scope.data);              element.html(template);             $compile(element.contents())(scope);         }     }; }]); 
like image 140
zim Avatar answered Sep 22 '22 12:09

zim


Had a similar need. $compile does the job. (Not completely sure if this is "THE" way to do it, still working my way through angular)

http://jsbin.com/ebuhuv/7/edit - my exploration test.

One thing to note (per my example), one of my requirements was that the template would change based on a type attribute once you clicked save, and the templates were very different. So though, you get the data binding, if need a new template in there, you will have to recompile.

like image 37
nowk Avatar answered Sep 25 '22 12:09

nowk


You should move your switch into the template by using the 'ng-switch' directive:

module.directive('testForm', function() {
    return {
        restrict: 'E',
        controllerAs: 'form',
        controller: function ($scope) {
            console.log("Form controller initialization");
            var self = this;
            this.fields = {};
            this.addField = function(field) {
                console.log("New field: ", field);
                self.fields[field.name] = field;
            };
        }
    }
});

module.directive('formField', function () {
    return {
        require: "^testForm",
        template:
            '<div ng-switch="field.fieldType">' +
            '    <span>{{title}}:</span>' +
            '    <input' +
            '        ng-switch-when="text"' +
            '        name="{{field.name}}"' +
            '        type="text"' +
            '        ng-model="field.value"' +
            '    />' +
            '    <select' +
            '        ng-switch-when="select"' +
            '        name="{{field.name}}"' +
            '        ng-model="field.value"' +
            '        ng-options="option for option in options">' +
            '        <option value=""></option>' +
            '    </select>' +
            '</div>',
        restrict: 'E',
        replace: true,
        scope: {
            fieldType: "@",
            title: "@",
            name: "@",
            value: "@",
            options: "=",
        },
        link: function($scope, $element, $attrs, form) {
            $scope.field = $scope;
            form.addField($scope);
        }
    };
});

It can be use like this:

<test-form>
    <div>
        User '{{!form.fields.email.value}}' will be a {{!form.fields.role.value}}
    </div>
    <form-field title="Email" name="email" field-type="text" value="[email protected]"></form-field>
    <form-field title="Role" name="role" field-type="select" options="['Cook', 'Eater']"></form-field>
    <form-field title="Sex" name="sex" field-type="select" options="['Awesome', 'So-so', 'awful']"></form-field>
</test-form>
like image 36
Aquajet Avatar answered Sep 22 '22 12:09

Aquajet