问题
I preciously asked on SO if it was possible to transclude the inner contents of a directive twice in the directive template (clone it and insert it in two places in the template).
A very helpful person helped me put this plunkr together.
http://plnkr.co/edit/k2UB1o4CTHtZ1voS0OKN?p=preview
It seems to work at first. The problem comes when I use any child element which uses transclusion itself. The error I get is...
[ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element:
For example I have a button directive with the following definition.
angular.module('s4p.directives').directive('s4pButton', function () {
return {
restrict: 'E',
scope: {
icon: '@'
},
transclude: true,
replace: true,
template: getTemplate
};
function getTemplate(element, attr) {
var btnType = (typeof attr.type === 'undefined') ? 'button' : attr.type;
return '<button s4p-button type="' + btnType + '">'+
'<s4p-button-content ng-transclude></s4p-button-content>'+
'<s4p-button-icon ng-if="icon">'+
'<s4p-icon href="{{icon}}"></s4p-icon>'+
'</s4p-button-icon>'+
'</button>';
}
});
as soon as I put one of my buttons inside the tool bar and it tries to clone it I get the above error.
EDIT:
New PLUNKR with full example
http://plnkr.co/edit/uK8r4EA2IPRnYKfjWNVG?p=preview
Any help would be greatly appreciated.
回答1:
Problem Code
The directive was trying to do the double transclusion in one invocation of the transclude function.
//PROBLEM Code
link: function(scope, element, attrs, controller, transclude) {
transclude(function(clone, scope) {
element.find('[transclude-main]').replaceWith(clone);
element.find('[transclude-overflow]').replaceWith($compile(clone.clone())(scope));
});
}
Correct Code
To transclude the directive contents into two places in the template, invoke the transclusion function twice.
app.directive('toolbar', function($compile) {
return {
restrict: 'E',
scope: {},
transclude: {
},
template:
'<toolbar-main><div transclude-main></div></toolbar-main>' +
'<toolbar-overflow><div transclude-overflow></div></toolbar-overflow>',
//CORRECTED code
link: function(scope, element, attrs, controller, transclude) {
transclude(scope, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
transclude(scope, function(clone) {
element.find('[transclude-overflow]').replaceWith(clone);
});
}
};
});
If you need new scopes for the transclusion, you can create them with scope.$new()
.
var newScope = scope.$new();
transclude(newScope, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
For more information on creating new scopes, see AngularJS $rootScope.scope API Reference -- $new.
Using AngularJS jqLite
AngularJS jqLite is a tiny, API-compatible subset of jQuery that allows Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most commonly needed functionality with the goal of having a very small footprint.1
The find
method of jqLite does not support attribute selectors. To make
the above example compatible with jqLite, use custom tags for the transclusion targets.
app.directive('toolbar', function($compile) {
return {
restrict: 'E',
scope: {},
transclude: {},
template:
'<toolbar-main><my-main></my-main></toolbar-main>' +
'<toolbar-overflow><my-overflow></my-overflow></toolbar-overflow>',
//CORRECTED code
link: function(scope, element, attrs, controller, transclude) {
transclude(scope, function(clone) {
element.find('my-main').replaceWith(clone);
});
transclude(scope, function(clone) {
element.find('my-overflow').replaceWith(clone);
});
}
};
});
This way there is no need to add jQuery to the app as a dependency.
回答2:
The actual error is not from transclusion, but from the template property. From the piece of code you provided, you just need to make a small change in order to make it work (you assigned to template property a function without calling it)
From
template: getTemplate
To
template: getTemplate()
Although this may solve your problem, I'd suggest moving your templates into separated html files and not keeping it inline. It's pretty hard to debug and scale an inline HTML.
来源:https://stackoverflow.com/questions/35527228/illegal-use-of-ngtransclude-directive-in-the-template-when-doing-transclusion-m