In the angular documentation for the compile service (starting at line 412) there is a description of the transclude function that is passed into the linking function of a directive.
The relevant part reads:
function([scope], cloneLinkingFn, futureParentElement)
In which (line 212):
futureParentElement
: defines the parent to which thecloneLinkingFn
will add the cloned elements.
default:
$element.parent()
resp.$element
fortransclude:'element'
resp.transclude:true
.only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements) and when the
cloneLinkinFn
is passed, as those elements need to created and cloned in a special way when they are defined outside their usual containers (e.g. like<svg>
).See also the
directive.templateNamespace
property.
I fail to see the point of futureParentElement
however. It says
defines the parent to which the cloneLinkingFn will add the cloned elements.
But you do that in the cloneLinkingFn
itself like this:
transclude(scope, function (clone) {
some_element.append(clone);
});
And you can't use the transclude function without defining the cloning function in the first place.
What is the proper usage/a use for futureParentElement
?
The answer to this can be found by looking at the the git blame of compile.js
: the commit that added futureParentElement
is https://github.com/angular/angular.js/commit/ffbd276d6def6ff35bfdb30553346e985f4a0de6
In the commit there is a test that tests a directive svgCustomTranscludeContainer
directive('svgCustomTranscludeContainer', function() {
return {
template: '<svg width="400" height="400"></svg>',
transclude: true,
link: function(scope, element, attr, ctrls, $transclude) {
var futureParent = element.children().eq(0);
$transclude(function(clone) {
futureParent.append(clone);
}, futureParent);
}
};
});
by testing how compiling the html <svg-custom-transclude-container><circle cx="2" cy="2" r="1"></circle>
behaves:
it('should handle directives with templates that manually add the transclude further down', inject(function() {
element = jqLite('<div><svg-custom-transclude-container>' +
'<circle cx="2" cy="2" r="1"></circle></svg-custom-transclude-container>' +
'</div>');
$compile(element.contents())($rootScope);
document.body.appendChild(element[0]);
var circle = element.find('circle');
assertIsValidSvgCircle(circle[0]);
}));
So it looks like if you are creating an SVG image with a directive whose template wraps transcluded SVG content in <svg> ... </svg>
tags, then that SVG image won't be valid (by some definition), if you don't pass the correct futureParentElement
to $transclude
.
Trying to see what it actually means not to be valid, beyond the test in the source code, I created 2 directives based on the ones in the unit test, and used them to try to create an SVG image with partial circle. One using the futureParentElement
:
<div><svg-custom-transclude-container-with-future><circle cx="1" cy="2" r="20"></circle></svg-custom-transclude-container></div>
and one that is identical but that doesn't:
<div><svg-custom-transclude-container-without-future><circle cx="2" cy="2" r="20"></circle></svg-custom-transclude-container></div>
As can be seen at http://plnkr.co/edit/meRZylSgNWXhBVqP1Pa7?p=preview, the one with the futureParentElement
shows the partial circle, and the one without doesn't. The structure of the DOM appears identical. However Chrome seems to report that the second circle
element isn't an SVG node, but a plain HTML node.
So whatever futureParentElement
actually does under the hood, it seems to make sure that transcluded SVG content ends up being handled as SVG by the browser.
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