I implemented a directive that transcludes multiple fragments of child content into a template. It works but seems simpler than most of the examples I have seen, and raised a few questions about how transclusion works.
Here is the directive:
module.directive('myTransclude', function() {
return {
restrict: 'A',
transclude: true,
replace: true,
scope: true,
template: '<div style="border: 1px solid {{color}}"><div class="my-transclude-title"></div><div class="my-transclude-body"></div></div>',
link: function(scope, element, attrs, controller, transclude) {
// just to check transcluded scope
scope.color = "red";
transclude(scope, function(clone, scope) {
Array.prototype.forEach.call(clone, function(node) {
if (! node.tagName) {
return;
}
// look for a placeholder node in the template that matches the tag in the multi-transcluded content
var placeholder = element[0].querySelector('.' + node.tagName.toLowerCase());
if (! placeholder) {
return;
}
// insert the transcluded content
placeholder.appendChild(node);
});
});
}
}
});
and here is example usage:
<div ng-controller="AppController">
<div my-transclude>
<my-transclude-title> <strong ng-bind="title"></strong>
</my-transclude-title>
<my-transclude-body>My name is {{name}} and I've been transcluded!</my-transclude-body>
</div>
</div>
You can see it in action in this fiddle.
Please notice a few things:
- It matches fragments to template placeholders by element class, rather than explicitly defined child directives. Is there any reason to do this one way or another?
- Unlike many examples I've seen, it doesn't explicitly use the $compile service on the child fragments. It seems like Angular is compiling the fragments after transclusion, at least in this simple case. Is this always correct?
- It uses the (barely documented) transclude argument to the link function, rather than the other (barely documented) approach of injecting the $transclude local into the controller directive. After hearing so many admonitions not to manipulate DOM in controllers, the controller approach seems like an odd construct and it feels more natural to handle this in the link function. However, I tried it that way and it seems to work the same. Is there any difference between the two?
Thanks.
EDIT: to partially answer question #2, I discovered that you do need to explicitly compile transcluded content that is not cloned from the template where the directive was applied. See the difference in behavior here: http://jsfiddle.net/4tSqr/3/