From the directive Angular docs, I see the compile function has 3 parameters, one of which is transclude
. The only explanation the docs provide is:
transclude - A transclude linking function: function(scope, cloneLinkingFn).
I'm trying to understand what exactly you would do in the clone linking function. I don't even know what parameters get passed into it. I found one example that has one parameter called clone
that appears to be an HTML element. Are there other parameters available? Which HTML element is this exactly? I'm also looking at probably using transclude: 'element'
in my directive. Do the answers to those questions change when using 'element'
instead of true
?
I'm understanding transclusion with the simple examples, but I can't to seem to find more complex examples, especially with transclude: 'element'
. I'm hoping someone can provide a more thorough explanation about all this. Thanks.
EDIT: Completely and totally changing my answer and marking this as "Community Wiki" (meaning no points for me) as I was outright wrong when I answered this
As @Jonah pointed out below, here is a really good article on the compile option of directives and using the transclusion function
The basic idea is the compile function should return a linking function. You can use the transclusion function provided inside the linking function to take a clone of the transcluded DOM element, compile it, and insert it wherever it needs to be inserted.
Here is a better example I've pulled out of my butt on Plunker
The idea of the compile function is it gives you a chance to programmatically alter the DOM elements based on attributes passed BEFORE the linking function is created and called.
// a silly directive to repeat the items of a dictionary object.
app.directive('keyValueRepeat', function ($compile){
return {
transclude: true,
scope: {
data: '=',
showDebug: '@'
},
compile: function(elem, attrs, transclude) {
if(attrs.showDebug) {
elem.append('<div class="debug">DEBUG ENABLED {{showDebug}}</div>');
}
return function(scope, lElem, lAttrs) {
var items = [];
console.log(lElem);
scope.$watch('data', function(data) {
// remove old values from the tracking array
// (see below)
for(var i = items.length; i-- > 0;) {
items[i].element.remove();
items[i].scope.$destroy();
items.splice(i,1);
}
//add new ones
for(var key in data) {
var val = data[key],
childScope = scope.$new(),
childElement = angular.element('<div></div>');
// for each item in our repeater, we're going to create it's
// own scope and set the key and value properties on it.
childScope.key = key;
childScope.value = val;
// do the transclusion.
transclude(childScope, function(clone, innerScope) {
//clone is a copy of the transcluded DOM element content.
console.log(clone);
// Because we're still inside the compile function of the directive,
// we can alter the contents of each output item
// based on an attribute passed.
if(attrs.showDebug) {
clone.prepend('<span class="debug">{{key}}: {{value}}</span>');
}
//append the transcluded element.
childElement.append($compile(clone)(innerScope));
});
// add the objects made to a tracking array.
// so we can remove them later when we need to update.
items.push({
element: childElement,
scope: childScope
});
lElem.append(childElement);
}
});
};
}
};
});
Success story sharing
TypeError: Cannot read property '1' of null
. This is because you are passing an element into the first argument of the transcludeLinkingFn and it expects a scope. It's spelled out clearly in the docs:transclude - A transclude linking function: function(scope, cloneLinkingFn).
Examples like this are not an intended use case. This article shows a better one.Note: The transclude function that is passed to the compile function is deperecated, as it e.g. does not know about the right outer scope. Please use the transclude function that is passed to the link function instead.
This is due to it having it's scope pre-bound.