Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the transclude option of directive definition?

People also ask

What does transclude option of a directive do?

Transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.

What is transclude in AngularJS directive?

The ng-transclude directive facilitates AngularJS to capture everything that is put inside the directive in the markup and use it somewhere in the directive's template.

How to define directive in AngularJS?

AngularJS directives are extended HTML attributes with the prefix ng- . The ng-app directive initializes an AngularJS application. The ng-init directive initializes application data. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

What is restrict option in directive?

Directive comes with many Directive Definition Objects (DDO). From them restrict is one. Using restrict option inside a Custom Directive we can prevent the access level of Directive for Element(E), Attribute(A), Comment(M) or Class(C).


Consider a directive called myDirective in an element, and that element is enclosing some other content, let's say:

<div my-directive>
    <button>some button</button>
    <a href="#">and a link</a>
</div>

If myDirective is using a template, you'll see that the content of <div my-directive> will be replaced by your directive template. So having:

app.directive('myDirective', function(){
    return{
        template: '<div class="something"> This is my directive content</div>'
    }
});

will result in this render:

<div class="something"> This is my directive content</div> 

Notice that the content of your original element <div my-directive> will be lost (or better said, replaced). So, say good-bye to these buddies:

<button>some button</button>
<a href="#">and a link</a>

So, what if you want to keep your <button>... and <a href>... in the DOM? You'll need something called transclusion. The concept is pretty simple: Include the content from one place into another. So now your directive will look something like this:

app.directive('myDirective', function(){
    return{
        transclude: true,
        template: '<div class="something"> This is my directive content</div> <ng-transclude></ng-transclude>'
    }
});

This would render:

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>. 

In conclusion, you basically use transclude when you want to preserve the contents of an element when you're using a directive.

My code example is here. You could also benefit from watching this.


I think it is important to mention changes in the above behaviour in new version of AngularJS. I spent one hour trying to achieve above results with Angular 1.2.10.

Contents of the element with ng-transclude are not appended but completely replaced.

So in the above example, what you would achieve with 'transclude' would be:

<div class="something">
    <button>some button</button>
    <a href="#">and a link</a>
</div>

and not

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>

Thanks.


What TechExplorer says is true but you can have both contents by including in your template a simple container tag (like div or span) with the ng-transclude attribute. This means that the following code in your template should include all content

<div class="something"> This is my directive content <div class="something" ng-transclude></div></div>

From Wiki:

"In computer science, transclusion is the inclusion of part or all of an electronic document into one or more other documents by reference."

I'd like to add another use for transclusion, and that is that it changes the execution order of the compile and link functions of parent and child directives. This can be useful when you want to compile the child DOM before the parent DOM as the parent DOM perhaps depends on the child DOM. This article goes more in depth and clarifies it very well!

http://www.jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives-part-2-transclusion/


The Updated AngularJS 1.6.6 documentation now has a better explanation.

Transclude is Used to Create a Directive that Wraps Other Elements

Sometimes it's desirable to be able to pass in an entire template rather than a string or an object. Let's say that we want to create a "dialog box" component. The dialog box should be able to wrap any arbitrary content.

To do this, we need to use the transclude option. Refer to the example below.


script.js

angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {
  $scope.name = 'Tobias';
}])
.directive('myDialog', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    templateUrl: 'my-dialog.html',
    link: function(scope) {
      scope.name = 'Jeff';
    }
  };
});

index.html

<div ng-controller="Controller">
  <my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>

my-dialog.html

<div class="alert" ng-transclude></div>

Compiled Output

<div ng-controller="Controller" class="ng-scope">
  <my-dialog class="ng-isolate-scope"><div class="alert" ng-transclude="">Check out the contents, Tobias!</div></my-dialog>
</div>

Transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.

This is illustrated in the previous example. Notice that we've added a link function in script.js that redefines name as Jeff. Ordinarily, we would expect that {{name}} would be Jeff. However, we see in this example that the {{name}} binding is still Tobias.

Best Practice: only use transclude: true when you want to create a directive that wraps arbitrary content.