AngularJS directive with multiple templates

17,996

Solution 1

Personally I think that Option 2 offers a clean separation between display modes. I have created a working CodePen example to illustrate how you might accomplish this cleanly by using separate directives for each template.

The method I used in my CodePen example utilizes a template factory which is injected into each directive via Angular DI. The template factory implementation is very clean since it merely uses ng-include template strings for each of the different supported display modes (compact & detailed). The actual HTML templates (partials) can be housed in external view files or internal script blocks.

Using the contact directives are easy:

<contact compact ng-repeat="contact in contacts" ng-model="contact"></contact>

This creates a compact version of the contact list.

<contact detailed ng-repeat="contact in contacts" ng-model="contact"></contact>

This creates a detailed contact listing.

I will admit that I haven't deployed code like this to production so there may be scalability or other concerns I haven't considered. I hope the code I provided answers your questions or at least provides inspiration for further exploration.

Solution 2

I have build a new approach working on Adam example and using also the sample from angular docs in which they talk about functions in templateUrl property https://docs.angularjs.org/guide/directive, this is the plunker from angular docs: http://plnkr.co/edit/h2CSf2WqCLYfPvzL9WQn?p=preview

.directive('myCustomer', function() {
    return {
      templateUrl: function(elem, attr){
        return 'customer-'+attr.type+'.html';
      }
    };
  });

And this is my remixed solution:

http://codepen.io/anon/pen/wawOyz?editors=101

app.factory('templates', function() {
  return {
    compact:   'compact',
    detailed:  'detailed'
  };
 });

app.directive('contact', function(templates) {
  return {
    restrict: 'E',
    templateUrl: function($elem, $attr){
      return templates[$attr.mode];       
    },
    scope: {
      contact: '=ngModel'
    }
  };
});

I liked the idea of having all template addresses in one factory but I find the directive-per-mode quite repetitive and if you have several elements using this approach you will need to namespace them (contact-text, email-text, company-text) so they don't crash.

I am not sure yet if this is a better way to go, is shorter and more DRY, but maybe is more difficult to test or less customizable. I just wanted to share the approach in case it can help anyone.

Share:
17,996

Related videos on Youtube

Stanislav Yermakov
Author by

Stanislav Yermakov

Updated on June 14, 2022

Comments

  • Stanislav Yermakov
    Stanislav Yermakov about 2 years

    Task:

    • To show contact.
    • Contact is JSON data, let's say {name: "Mark", location: "England", phones: [...]}.
    • Contact could be shown in multiple ways: compact / detailed / enhanced with additional info (shared contacts - additional directive)

    Because contact could be shown on different pages in different places it's naturally to create directive (widget) for contact, but here is question: "How to organize same widget with multiple templates?"

    Options:

    1. Create one directive with one template, that hides sections according to contact "type" - big template with possibly a lot of ng-switch and ng-if
    2. Create directive for each template - almost same directives with only different template (or templateURL)
    3. To load templates dynamically while linking - has problems with transclusion and replacing (merging attributes)

    Whats your expirience with solving these problem?

    • Zack Argyle
      Zack Argyle almost 11 years
      Do you need to stick a template inside the directive? Can you simply use a directive as an attribute next to an ng-include for your template?
    • Stanislav Yermakov
      Stanislav Yermakov almost 11 years
      Are you talking about solution suggested by Adam here?
  • Stanislav Yermakov
    Stanislav Yermakov almost 11 years
    Thanks for response even with example ). Your right, if directives are so small, it's not critical to have one for each type, but it gives flexibilyty, to enhance one of them only when it's necessary.
  • Stanislav Yermakov
    Stanislav Yermakov almost 11 years
    Only I can add, What for to use ng-include as template? Why not to use "templates" factory just as map "contact type"=>"url to template", do you see any profit of it?