Understanding AngularJS Transclusion Directive

Written by tommybernaciak | Published 2020/09/29
Tech Story Tags: javascript | angularjs | directive | programming | coding | software-development | software-engineering | angular

TLDR The transclusion directive is a way of including content from one template to another. Transclusion allows you to nest the content as HTML inside your directive tag. It is a very good solution for making consistent cards in every place it is needed. It allows you not needlessly repeat yourself when creating directives in your application and to make your templates more versatile. I really recommend using it often across your application directives, and it is easy to use it with a real-life example. The directive is something that is not described properly with AngularJS docs, but with a little explanation and real life example, it becomes easy.via the TL;DR App

A
ngTransclude
directive is a thing I often found in many examples, yet I think it is not well explained in the official docs. I was never really sure how to use it, and I am sure I am not the only one. As I found, the general concept is not difficult, but documentation, which uses lots of big words, makes it hard to understand. I decided to create a quick user guide to describe how you can use
ng-transclude
with a short but expository example.

Basic directive — without transclusion

To explain transclusion in one sentence you could say that it is a way of including content from one template to another. Imagine a simple situation. You have a directive for a card with some data. It contains three elements — header, content and button. The template can look like this:
<div class="card">
  <h1 class="header">{{header}}</h1>
  <div class="content">{{content}}</div>
  <button
    type="submit"
    class="button"
    ng-click="buttonAction()">
    {{buttonText}}
  </button>
</div>
This HTML template allows you to use this card everywhere you want. This requires a code for a directive, for example, something like this:
(function() {
  'use strict';

  angular
    .module('app.card')
    .directive('Card', Card);

  function Card() {
    return {
      restrict: 'E',
      replace: true,
      scope: {
        header: '@',
        content: '@',
        buttonAction: '&',
        buttonText: '@'
      },
      templateUrl: 'card.html'
    };
  }
})();
It is very simple; data binding allows you to bind attributes values to this template. A
header
,
content
and
buttonText
are bound as text in the places where corresponding expressions occur. You can also pass a function to a button using
buttonAction
. It can be done as simple as this:
<card 
  header="Hello"
  content="Do you want to continue?"
  button-text="Nope"
  button-action="$ctrl.close()">
</card>
It is a very good solution for making consistent cards in every place it is needed. When you want to change how the card looks like to the user, just apply changes to the template and you will get a discernible effect in every place that this directive is used.

More flexibility — transclusion

Although this directive gives you a little flexibility, it doesn’t really allow you to add something more to it. This doesn’t let us use HTML formatting in the content. Imagine that instead of simple text binding, you want now to add something more sophisticated to your card content. This is what transclusion is used for, to nest the content as HTML inside it. The brilliance of transclusion is that everything you put inside your directive tag can be displayed in a particular place in your template. As an example, you want to add a simple table to the content. First, a template should be changed.
<div class="card">
  <h1 class="header">{{header}}</h1>
  <div class="content" ng-transclude="cardContent"></div>
  <button
    type="submit"
    class="button"
    ng-click="buttonAction()">
    {{buttonText}}
  </button>
</div>
The same changes are required in the directive, now the content will be transcluded:
(function() {
  'use strict';

  angular
    .module('app.card')
    .directive('Card', Card);

  function Card() {
    return {
      restrict: 'E',
      replace: true,
      transclude: {
        cardContent: 'cardContent'
      }
      scope: {
        header: '@',
        buttonAction: '&',
        buttonText: '@'
      },
      templateUrl: 'card.html'
    };
  }
})();
And now you can use it as you want. You can put whatever inside your directive html tag and it will be displayed inside a
div
with
cardContent
transclusion. You can add a simple table inside:
<card 
  header="Table"
  button-text="Close"
  button-action="$ctrl.close()">
  <table>
    <tr>
      <th>Firstname</th>
      <th>Lastname</th> 
      <th>Age</th>
    </tr>
    <tr>
      <td>Jill</td>
      <td>Smith</td> 
      <td>50</td>
    </tr>
    <tr>
      <td>Eve</td>
      <td>Jackson</td> 
      <td>94</td>
    </tr>
  </table>
</card>
It will result with this HTML code in the end:
<div class="card">
  <h1 class="header">Table</h1>
  <div class="content">
    <table>
      <tr>
        <th>Firstname</th>
        <th>Lastname</th> 
        <th>Age</th>
      </tr>
      <tr>
        <td>Jill</td>
        <td>Smith</td> 
        <td>50</td>
      </tr>
      <tr>
        <td>Eve</td>
        <td>Jackson</td> 
        <td>94</td>
      </tr>
    </table>
  </div>
  <button
    type="submit"
    class="button"
    ng-click="$ctrl.close()">
    Close
  </button>
</div>
As you see values of every attributes are bound to selected elements and table was inserted to content
div
.

Conclusion

The transclusion directive is something that is not described properly with AngularJS docs, but with a little explanation and real-life example, it becomes very easy. It allows you to not needlessly repeat yourself when creating directives in your application and to make your templates more versatile. I really recommend using it often across your application directives.
This story was originally published on my Medium page on Nov 14, 2017 and had 1.4K views when moved to my Hackernoon page.

Written by tommybernaciak | Full Stack Dev
Published by HackerNoon on 2020/09/29