Directive transclusion
Transclusion on its own is a relatively simple construct in AngularJS. This simplicity becomes muddied when mixed with the complexity of directives and scope inheritance. Directive transclusion is frequently used when the directive either needs to inherit from the parent scope, manage nested HTML, or both.
How to do it…
Assemble all the pieces required to use transclusion. This is shown here:
(index.html - uncompiled) <div ng-app="myApp"> <div ng-controller="MainCtrl"> <my-directive> <p>HTML template</p> <p>Scope from {{origin}}</p> <p>Overwritten? {{overwrite}}</p> </my-directive> </div> <script type="text/ng-template" id="my-directive.html"> <ng-transclude></ng-transclude> </script> </div> (app.js) angular.module('myApp', []) .controller('MainCtrl', function ($scope) { $scope.overwrite = false; $scope.origin = 'parent controller'; }) .directive('myDirective', function() { return { restrict: 'E', templateUrl: 'my-directive.html', scope: {}, transclude: true, link: function (scope) { scope.overwrite = !!scope.origin; scope.origin = 'link function'; } }; });
This will compile into the following:
(index.html – compiled) <p>HTML template</p> <p>Scope from parent controller</p> <p>Overwritten? false</p>
In the directive's template, the location of ng-transclude
informs $compile
that the directive's original HTML contents are to replace the contents of the specified element. Furthermore, using transclusion means that the parent scope will continue to be in the directive to be used for the interpolated HTML.
To see the main reason to use transclusion more clearly, modify the my-directive.html
directive template slightly in order to see the results side by side. This can be done as follows:
(index.html - uncompiled) <script type="text/ng-template" id="my-directive.html"> <ng-transclude></ng-transclude> <hr /> <p>Directive template</p> <p>Scope from {{origin}}</p> <p>Overwritten? {{overwrite}}</p> </script>
This will compile into the following:
(index.html - compiled) <p>HTML template</p> <p>Scope from parent controller</p> <p>Overwritten? false</p> <hr /> <p>Directive template</p> <p>Scope from link function</p> <p>Overwritten? false</p>
Tip
JSFiddle: http://jsfiddle.net/msfrisbie/1a11d3mk/
How it works…
It should now be apparent exactly what is going on inside the directive that uses transclusion. The directive's template is subject to the link
function (which necessarily uses the isolate scope), and the original wrapped HTML template maintains its relationship with the parent scope without the directive interfering.
See also
- The Directive scope inheritance recipe goes over the basics that involve carrying the parent scope through a directive
- The Directive templating recipe examines how a directive can apply external scope to an interpolated template
- The Isolate scope recipe details how a directive can be decoupled from its parent scope