Sunday, 24 March 2013

AngularJS directives: transclude attribute


In the previous blog item we saw that just using the template attribute, was not enough to create our panel widget. AngularJS will always replace the contents of the element where we have placed the directive on.

Unless we refer to the contents in our template, this is how we can do it. The code can be found here.

Transclude attribute

We change the html code a bit so that we can test if we can have also a dynamic contents within the panel.
<div my-dir2 title="{{panelTitle}}" >Contents of the div. Angular Expression result : {{contentField}}</div>

With the transclude attribute we indicate that we need the contents of the element. We can assign this contents to an element specified in the template by using the ng-transclude directive. 

The directives looks now like this (again the CSS info is omitted for clarity)
demo.directive('myDir2', function version2() {
        return {
            restrict: 'EA'
            , replace: true
            , scope: {title: '@title'}
            , template: '<div> Panel title {{title}}<div ng-transclude></div></div>'
            , transclude: 'element'
The result now is that we have a div with the title in and another div which contains the original contents.
And the good thing is, is stays AngularJS aware. So the contents which contains an expression still reacts to changes on the model value. In the example code on github, which has the CSS information, the results looks more or less like a proper panel widget.


Loose ends

When you remove the replace attribute, or set it to false, our widget complete vanishes.  The reason for this is that we specified the string ‘element’ as the value of the transclude attribute. However, the technical reason is not clear.

Another possibility is that we specify the boolean value true for the transclude attribute and then the replace value doesn’t matter.
With ‘element’ we specify that the element itself is also made available in the transcluded result and further processed. There could be other directives which don’t get the chance do to there work.  So ‘element’ is the best option in my opinion at the cost that you shouldn’t forget to specify the replace attribute.


Using the transclude attribute, we have realised a first simple version of the panel widget we had in mind.  But it is not the end of our journey.
We can’t specify the option to have a collapse/expand button. With the template attribute, we can’t fix it because a template is always static.

Therefor we need a more dynamic solution and that is where the compile and link concepts and functions come into the picture.  Enough stuff for the next blog item.


  1. Hi,
    I'm developing with JSF (IceFaces... but I would prefer Prime :) ) and I'm willing to dive into JS. I started looking at some frameworks, Angular in particular.
    Is "ng" able to replace/add html tags, right?

    Good job, thank you

  2. With AngularJS, you can indeed replace and/or add html tags like I did in the example. But DOM manipulation is normally restricted to directives where you can change the structure of your page.

    If you come from a JSF background, you can see the resemblance. See also my blog item where I compare JSF and AngularJS.


  3. Nice post....good explanation/use of transclude.