I was reading about ng-transclude
in the AngularJS docs on Creating a Directive that Wraps Other Elements and I think I understand properly what it does.
If you have a directive that applies to an element that has content inside it such as the following:
<my-directive>directive content</my-directive>
it will allow you to tag an element within the directive's template with ng-transclude
and the content included in the element would be rendered inside the tagged element.
So if the template for myDirective
is
<div>before</div>
<div ng-transclude></div>
<div>after</div>
it would render as
<div>before</div>
<div ng-transclude>directive content</div>
<div>after</div>
My question is if it is possible to somehow pass more then a single block of html into my directive?
For example, suppose the directive usage would look like this:
<my-multipart-directive>
<part1>content1</part1>
<part2>content2</part2>
</my-multipart-directive>
and have a template like:
<div>
this: <div ng-transclude="part2"></div>
was after that: <div ng-transclude="part1"></div>
but now they are switched
<div>
I want it to render as follows:
<div>
this: <div ng-transclude="part2">content2</div>
was after that: <div ng-transclude="part1">content1</div>
but now they are switched
<div>
Perhaps I could somehow bind the HTML value of a node to the model so that I will be able to use it in such a way without calling it "transclude"?
Starting Angular 1.5, it's now possible to create multiple slots. Instead of transclude:true, you provide an object with the mappings of each slot:
https://docs.angularjs.org/api/ng/directive/ngTransclude
angular.module('multiSlotTranscludeExample', [])
.directive('pane', function(){
return {
restrict: 'E',
transclude: {
'title': '?pane-title',
'body': 'pane-body',
'footer': '?pane-footer'
},
template: '<div style="border: 1px solid black;">' +
'<div class="title" ng-transclude="title">Fallback Title</div>' +
'<div ng-transclude="body"></div>' +
'<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
'</div>'
};
})
Cool question. I'm not sure there is a built in way, but you can do it yourself in a pretty generic way.
You can access the transcluded element by passing in the $transclude service like this:
$transclude(function(clone, $scope) {
Where clone will be a copy of the pre-linked transcluded content. Then if you label the content in the element like this:
<div id="content">
<div id="content0">{{text}}</div>
<div id="content1">{{title}}</div>
</div>
You can loop over the content and compile it like this:
$scope.transcludes.push($compile(clone[1].children[i])($scope));
Great! now you just need to put the content in the correct place in your template
'<div id="transclude0"></div>' +
'<div id="transclude1"></div>' +
Then you can in your link function assign the content correctly
angular.element(document.querySelector('#transclude' + i)).append(scope.transcludes[i]);
I set up a fiddle you can play with that has this set up.
Hope this helped!
In our project we have modeled multi site trasclusion after JSF 2's ui:composition, ui:insert, ui:define (see ui:composition).
Implementation consists of three simple directives: ui-template, ui-insert, ui-define (see angularjs-api/template/ui-lib.js).
To define a template one writes the following markup (see angularjs-api/template/my-page.html):
<table ui-template>
<tr>
<td ui-insert="menu"></td>
</tr>
<tr>
<td ui-insert="content"></td>
</tr>
</table>
and declares a directive (see angularjs-api/template/my-page.js):
var myPage =
{
templateUrl: "my-page.html",
transclude: true
};
angular.module("app").
directive("myPage", function() { return myPage; });
and finally, to instantiate the directive one needs to write (see angularjs-api/template/sample.html):
<my-page>
<div ui-define="content">
My content
</div>
<div ui-define="menu">
<a href="#file">File</a>
<a href="#edit">Edit</a>
<a href="#view">View</a>
</div>
</my-page>
The working sample can be seen through rawgit: sample.html
See also: Multisite Transclusion in AngularJS
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With