AngularJS Directive’s transclude & ng-transclude can be used to create directive that wraps other elements. By-default, AngularJS Directive element replaces any element declared as a child element of directive in HTML, by directive’s own content. But sometimes you way want to preserve the child element and let the directive act as more of a wrapper rather than replacement. This can be done thanks to transclude & ng-transclude.
Let’s understand it with help of few examples. In all our previous examples, you have noticed that there is no child-element added under a directive element. Now if you try to wrap an element by a directive, something like shown below:
<div ng-repeat="bla in ctrl.items"> <item-widget item="bla" promo="Christmas-Sale" on-select="ctrl.onItemSelect(selectedItem)"> Last item left. Hurry up. </item-widget> </div>
on execution, you will see that child element of this widget [that poor dummy message] is found nowhere. It gets kicked out by directive’s own content [template]. There might however be cases when we want to preserve the child element of a directive, OR in other words, wrap the existing content by the directive’s own content.
AngularJS provides transclude
option and ng-transclude
directive to help with this issue. It’s a two step process:
How it works?
transclude
set to true, AngularJS will make a copy of content the directive is applied on, and will store it somewhere so that it does not get lost when angular replaces it with directive’s own template.Live Example:
Let’s get into details:
<div ng-repeat="bla in ctrl.items"> <item-widget item="bla" promo="Christmas-Sale" on-select="ctrl.onItemSelect(selectedItem)"> Last item left. Hurry up. </item-widget> </div> .directive('itemWidget', [function() { return{ transclude:true, ...//other options as in previous examples. } }]);
Firstly, We have included dummy content as child of our custom widget, and our intention would be to preserve it. Next, we have declarted transclude
key with value true.
Now let’s see the directive’s template [saleItem6.html]
<div class="panel panel-default"> <div class="panel-heading"> Published at:<span ng-bind="item.published | date"></span> Promotion: {{promo}}<button class="pull-right" ng-click="pickMe({selectedItem:item.name})">Buy me</button> </div> <div class="panel-body"> <div class="alert alert-info" ng-transclude></div> Name:<span ng-bind="item.name"></span> Condition:<span ng-bind="item.condition"></span> Price:<span ng-bind="item.price | currency"></span> Brand:<span ng-bind="item.brand"></span> </div> </div>
In above directive’s template file, we have included ng-transclude
with a div. AngularJS will copy the content of the element it finds when it encounters our directive in HTML, and make it as a child element of this div element with ng-transclude.
Complete code
<html> <head> <title>Directive Demo</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/> </head> <body class="jumbotron container" ng-app="myApp"> <div ng-controller="AppController as ctrl"> <h3>List of Sale Items.</h3> <div ng-repeat="bla in ctrl.items"> <item-widget item="bla" promo="Christmas-Sale" on-select="ctrl.onItemSelect(selectedItem)"> Last item left. Hurry up. </item-widget> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"> </script> <script> angular.module('myApp', []) .controller('AppController', [function() { var self = this; self.items = [ {name: 'Computer', price: 500, condition:'New',brand : 'Lenovo', published:'01/11/2015'}, {name: 'Phone', price: 200, condition:'New',brand : 'Samsung', published:'02/11/2015'}, {name: 'Printer', price: 300, condition:'New',brand : 'Brother', published:'06/11/2015'}, {name: 'Dishwasher', price: 250, condition:'Second-Hand',brand : 'WhirlPool', published:'01/12/2015'}, ]; self.onItemSelect = function(name) { console.log('Congrats. You have just bought a', name); }; }]) .directive('itemWidget', [function() { return{ restrict: 'E', replace:true, transclude:true, scope: { item: '=', promo: '@', pickMe : '&onSelect' }, templateUrl: 'saleItem6.html', link : function(scope, element, attrs){ //Add event listener for 'click' event element.on('click', function(event) { element.html('Thanks for buying this item.'); element.css({ color: 'green' }); }); } } }]); </script> </body> </html>
That’s it for transclude option with ngTransclude. Let’s move to advanced link-function configuration option [require
] of Directive Definition Object where we discuss inter-directive communication in detail using directive’s controllers.
You can use popular Apache HTTP server to serve files. If you need assistance setting-up server,
this post can help you.
References
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help improve further our learning process.
In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…
Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…
Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…
Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…
Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…
This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…
View Comments
Thanks WebSystique !!! This series is really helpful specially the example part.
Also it would be really great if you could provide some example on pre-link, post-link and compile part of the directive.