Architectural Blog, Modern Buildings & Casino Designs Loading...

AngularJS Directive with dynamic template

I came across the need for this recently and it was pretty easy to achieve so this should be a quick one.

In my case I had to build a dynamic form from JSON. An endpoint would send me JSON representing a form with a seemingly random amount of fields – of varying types and also some other conditional behaviour which I will spare from hearing about here.

Heres an example of the kind of thing I might expect to see – simplified a bit (a lot) for sake of example.

[  {    type: 'text',    data: '',    label: 'Name'  },  {    type: 'email',    data: '',    label: 'Email address'  },  {    type: 'select',    data: '',    label: 'Animal',    options: ['Cat','Dog','Fish']  }]

There were actually about 5 other types I would be sent too, and with extra functionality – I only tell you this so you don’t think this approach is a bit heavy-handed for something as simple as this example.

I decided I wanted to use a single directive for these fields, but seeing as each one needed to be be represented differently I wanted each type to have its own template. The directive is pretty simple:

angular.module('exampleApp').directive('dynamicField', function() {  return {    restrict: 'E',    replace: true,    scope: {      fieldData: '='    },    link: function(scope, element, attrs) {      // Function returns the correct template for each field.      scope.getTemplateUrl = function() {        var type = scope.fieldData.type || 'text';        return 'dynamic-fields/dynamic-field-'+type+'.html';      }    },    template: '<div class="dynamic-field" ng-include="getTemplateUrl()"></div>'  };});

So assuming I have the fields on the scope of my controller I would loop through them like so:

<form>  <dynamic-field field-data="fieldData" ng-repeat="fieldData in fields"></dynamic-field>  <input type="submit" value="Submit" /></form>

So this provides the fieldData to the directive, which contains the type (any anything else the field requires) and the directive used the correct template. Heres an example of the dynamic-field-text.html template:

<label>{{fieldData.label}}</label><input type="text" ng-model="fieldData.data" />

And the dynamic-field-select.html template:

<label>{{fieldData.label}}</label><select ng-model="fieldData.data" ng-options="o as o for o in fieldData.options">  <option value="">-- Pick one --</option></select>

Pretty simple huh!