AngularJS provides the lots of important features with their easy uses. But, when we talk about transclusion, which is one of the important features of angular, it creates some confusion among users regarding its proper uses.

So, in this blog, we are going to explain transclusion from the very basic level so that you can easily catch up the concepts and uses of transclusion.

Transclusion

Transclusion is a process of including the content of one template into another. It provides us the flexibility to use a custom directive in more efficient manner.

Need of Transclusion:

Let’s understand the need of transclusion through a simple example.

Suppose, we have a custom directive, demoText which purpose is to display a message “Custom Directive Data!!!.

controller.js

// Application module
angular.module('myApp',[])
// Register custom directive
.directive('demoText',function(){
return{
// Isolated scopes
scope:{},
// Template for this custom directive
template:'<div><p>Custom Directive Data!!!</p></div>'
};
});

Now, we have used the above-mentioned custom directive in the index.html page of the application as:

index.html

<html ng-app="myApp">
<head>
// Include AngularJS and other library files here
</head>
<body>
<!-- Using custom directive as an element -->
<demo-text>
<p class="text-success">Successfully Transcluded!!!</p>
</demo-text>
</body>
</html>

Here, the custom directive is used as a element like, <demo-text>…</demo-text>.

 But, there is one thing to notice that between the custom directive tags, there is a paragraph tag contain a message “Successfully Transcluded!!!“.

Now, when compiler will compile the directive and will link it with the DOM by AngularJS, the paragraph with “Successfully Transcluded!!!” message will get replaced with the template of the custom directive, i.e Custom Directive Data!!!.

The output will be displayed as:AngularJS Directive Data

Note:- In all the codes dispalyed in the blog, we have removed the CSS and class from elements so that the code looks clear and concept could be understand easily.

But, you will get the code with complete CSS and design in download script.

It means that whenever the custom directive will be used in the application, it will replace all the content between its tag with the template of the directive.

But, when we need to display the content between the tags along with the template then what?

In such case, transclusion is the solution. It will include the content between tags in the template of the custom directive.

To achieve transclusion, first we will have to enable the transclude option of the directive by setting it to true. By doing this, we tell the directive to allow the transcluded content to use within the directive.

controller.js

// Register custom directive
.directive('demoText',function(){
return{
...
// Enable transclusion property for this custom directive
transclude:true,
...
};
});

Now, to display the content, there is two way.

1. ngTransclude:

AngularJS provide ngTransclude directive which clone the content (between directive tag) and add it to the DOM as a child element where ngTransclude directive is applied.

For example,

controller.js

// Register custom directive
.directive('demoText',function(){
return{
...
// Enable transclusion property for this custom directive
transclude:true,
// Template for this custom directive
template:'<div><p>Custom Directive Data!!!</p><div ng-transclude></div></div>'
};
});

Here, ng-transclude is applied on the div of custom directives’s template as an attribute. So, the content will be displayed along with the directive’s template wherever the custom directive will be used in the application.

In above case, the output will be displayed as:AngularJS ngTransclude Data


Download complete code from the link given below.


2. Transclude function:

Another way to show the content is to pass the fifth argument in the link function of the custom directive. It will act as a callback function and used to manipulate the cloned element or data.

For example,

controller.js

// Register custom directive
.directive('demoText',function(){
return{
...
// Enable transclusion property for this custom directive
transclude:true,
// Template for this custom directive
template:'<div class="alert alert-warning"><p class="text-info">Custom Directive Data!!!</p></div>',
// Passed transcludeFn callback function as fifth argument
link: function(scope, element, attrs, controller, transcludeFn){
transcludeFn(function(clone_data){

// Append this directive's template with the cloned content
element.append(clone_data);
});
}
};
});

Here, transcludeFn has passed as a fifth argument to directive’s link function, which will act a callback function. This function takes cloned element as an argument and append the directive’s element with the cloned element.

The output will be displayed something like this:AngularJS transcludeFn Data


Download complete code from the link given below.


Note:- The output of transcludeFn  function method will be different from the ngTransclude directive method because in transcludeFn method we are appending the element, directive’s template, with the cloned data.

However, in ngTransclude directive method, we are using ng-transclude as an attribute inside the div element of the directive’s template.

Application of transcludeFn:

Multiple clones of the content

One of the most important advantages of transcludeFn it that it allows you to use the cloned conted multiple time within your directive.

Fore example,

controller.js

// Register custom directive
.directive('demoText',function(){
return{
...
// Enable transclusion property for this custom directive
transclude:true,
// Template for this custom directive
template:'<div class="alert alert-warning"><p class="text-info">Custom Directive Data!!!</p></div>',
// Passed transcludeFn callback function as fifth argument
link: function(scope, element, attrs, controller, transcludeFn){
transcludeFn(function(clone_data){
// Append this directive's template with the cloned content
element.append(clone_data);
});
transcludeFn(function(clone_data){
// Append this directive's template with the cloned content
element.append(clone_data);
});
transcludeFn(function(clone_data){
// Append this directive's template with the cloned content
element.append(clone_data);
});
transcludeFn(function(clone_data){
// Append this directive's template with the cloned content
element.append(clone_data);
});
}
};
});

Here, you can see that transcludeFn(function(clone_data){ … }); is repeated multiple times inside the link function of the directive.

On each repetition, the cloned content will be appended with the new element of the directive, i.e each time in the directives template, a new clone element will be added. Such as,AngularJS transcludeFn Multiple Clone


Download complete code from the link given below.


You might be thinking that why we have used transcludedFn multiple times inspite of only appending the element multiple times in a single transcludeFn like,

controller.js

// Register custom directive
.directive('demoText',function(){
return{
...
// Enable transclusion property for this custom directive
transclude:true,
// Template for this custom directive
template:'<div class="alert alert-warning"><p class="text-info">Custom Directive Data!!!</p></div>',
// Passed transcludeFn callback function as fifth argument
link: function(scope, element, attrs, controller, transcludeFn){
transcludeFn(function(clone_data){
// Append this directive's template with the cloned content
element.append(clone_data);
element.append(clone_data);
element.append(clone_data);
element.append(clone_data);
element.append(clone_data);
});
}
};
});

Let me tell you that multiple element.append(clone_data); inside a single transcludeFn will append the template with the clone content only first time

Next time, it will overwrite the same cloned content again and again which will results in displaying the cloned content only once inspite of multiple times.

Using this method for cloning the content multiple times is totally useless. So, for multiple cloning use the first one.

Transclusion Scope:

One of the important advantages of transclusion is that it allow you to use the outer scope inside a custom directive, rather  than the isolated scope( directive’s own internal scope ).

It is more useful when we want to add some dynamic content as a transcluded content in the custom directive’s template.

Let’s generate the same output but using the outer scope. For this we will have to make some changes in the earlier codes.

controller.js

// Application module
angular.module('myApp',[])
// Main controller of the application
.controller('demoController',['$scope',function($scope){
$scope.success_msg = "Successfully Transcluded!!!";
}])
// Register custom directive
.directive('demoText',function(){
return{
// Isolated scopes
scope:{},
// Template for this custom directive
template:'<div><p>Custom Directive Data!!!</p></div>'
};
});

In the controller.js file, we have added a controller which store “Successfully Transcluded!!!” message in the main scope($scope) of the application.

Now, in index.html, just use scope property and evaluate the message using expression.

<html ng-app="myApp">
<head>
// Include AngularJS and other library files here
</head>
<body>
<div ng-controller="demoController">
<!-- Using custom directive as an element -->
<demo-text>
<p class="text-success">{{success_msg}}</p>
</demo-text>
</div>
</body>
</html>

Here, in the html page, instead of a static element we are using success_msg object, which contain the message.

Note:- success_msg is a property added to the parent scope($scope). It act as an outer scope for the custom directive.

So, from the above-mentioned example, it might be clear that how you can use and outer scope inside a custom directive.

$destroy

Whenever we call a transcludeFn callback function inside a link function, a scope is created for the transcluded content.

In such case, if we need to remove the transcluded content, then there is a possibility of memory/scope leaking. This is because angular know only about the removing action of the transcluded content and unaware of

This is because angular know only about the removing action of the transcluded content by tracking events but, unaware of the transcluded scopes i.e whether the scope is destroyed or not.

Thus, to remove the leaking probability of scope, angular provides $destroy event which destroy the transcluded scopes.

Have a look at the example given below.

In this example, following action will be performed.

  1. First, display custom directive’s content along with a button “Show transcluded message“.
  2. When this button will be clicked, a transcluded function will be called which will append and display the transcluded content along with the directive’s template and another button “Hide transcluded message”.
  3. When this button will be clicked, $destroy event will trigger which will destroy the transcluded scope. At the same time, the transcluded content will be removed and hide the transcluded message.

controller.js

// Application module
angular.module('myApp',[])
// Main controller of the application
.controller('demoController',['$scope',function($scope){
$scope.success_msg = "Successfully Transcluded!!!";
}])
// Register custom directive
.directive('demoText',function(){
return{
// Isolated scopes
scope:{},
// Enable transclusion property for this custom directive
transclude:true,
// Template for this custom directive
template:'<div class="alert alert-warning"><p class="text-info">Custom Directive Data!!!</p><button class="btn btn-success" ng-show="show_msg" ng-click="show_div()">Show Transcluded Message</button><p class="alert alert-success trans-msg"></p><button class="btn btn-danger" ng-hide="show_msg" ng-click="hide_div()">Hide Transcluded Message</button></div>',
// Passed transcludeFn callback function as fifth argument
link: function(scope, element, attrs, controller, transcludeFn){
scope.show_msg=true;
var tranContent = element.find('.trans-msg');
tranContent.css({"display":"none"});
// Function to show the transcluded message div
scope.show_div= function(){
scope.show_msg=false;
// Transclude callback function to add content in the directive template
transcludeFn(function(clone_data){
tranContent.html(clone_data).css({"display":"block","margin-bottom":"5px"});
});
}

// Function to remove and hide the transcluded message div
scope.hide_div= function(){
scope.show_msg=true;
// Transclude callback function to destroy transcluded scope
transcludeFn(function(clone_data, tranScope){
// Destroying transcluded content's scope & setting it to NULL
tranScope.$destroy();
tranScope=null;
});
// Remove transclude content from the directive
tranContent.empty().css({"display":"none"});
}
}
};
});

index.html

<html ng-app="myApp">
<head>
// Include AngularJS and other library files here
</head>
<body>
<div ng-controller="demoController">
<!-- Using custom directive as an element -->
<demo-text>
<p class="text-success">{{success_msg}}</p>
</demo-text>
</div>
</body>
</html>

Output for this example would be like this,AngularJS Transclude Destroy


Download complete code from the link given below.


Element Transclusion

Element transclusion is another awesome feature available in the AngularJS.

It allows  you to transclude the whole element rather than just some content. For this, you will have to replace transclude:true  with transclude:”element”  in the custom directive.

By doing so, you can get the whole element in spite some content. Now you can easily modify the clone element and add it to the DOM and so on.

One of the important advantages of element transclusion is that you can remove template option from custom directive and directly use the dynamic content in the custom directive.

Let’s see element transclusion through an example which will display the “Successfully Transcluded!!!” message without using any template in custom directive.

controller.js

// Application module
angular.module('myApp',[])
// Main controller of the application
.controller('demoController',['$scope',function($scope){
$scope.success_msg = "Successfully Transcluded!!!";
}])
// Register custom directive
.directive('demoText',function(){
return{
// Isolated scopes
scope:{},
// Setting transclusion as element
transclude:"element",
// Link function to display the transcluded element content
link: function(scope, element, attrs, controller, transcludeFn) {
transcludeFn(function(clone_element) {
element.after(clone_element);
});
},
};
});

index.html

<html ng-app="myApp">
<head>
// Include AngularJS and other library files here
</head>
<body>
<div ng-controller="demoController">
<!-- Using custom directive as an element -->
<demo-text>
<p class="text-success">{{success_msg}}</p>
</demo-text>
</div>
</body>
</html>

OutputAngularJS Element Transclude


Download complete code from the link given below.


Conclusion:

Hope this blog will help you in understanding the concepts and use of transclusion in AngularJS. Keep reading our blogs and comment us from the space given below 🙂