在模板中非法使用 ngTransclude 指令!手动进行嵌入时
Illegal use of ngTransclude directive in the template! when doing transclusion manually
我在 SO 上非常认真地询问是否可以在指令模板中两次嵌入指令的内部内容(克隆它并将其插入模板中的两个位置)。
一个非常有帮助的人帮我把这个 plunkr 放在一起。
http://plnkr.co/edit/k2UB1o4CTHtZ1voS0OKN?p=preview
一开始似乎可行。当我使用任何使用嵌入本身的子元素时,问题就来了。我得到的错误是...
[ngTransclude:orphan] 在模板中非法使用 ngTransclude 指令!找不到需要包含的父指令。元素:
例如,我有一个具有以下定义的按钮指令。
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>';
}
});
当我将其中一个按钮放入工具栏并尝试克隆它时,我收到了上述错误。
编辑:
带有完整示例的新 PLUNKR
http://plnkr.co/edit/uK8r4EA2IPRnYKfjWNVG?p=preview
如有任何帮助,我们将不胜感激。
实际错误不是来自嵌入,而是来自模板 属性。从您提供的这段代码中,您只需要做一点小改动就可以让它工作(您为模板 属性 分配了一个函数而不调用它)
来自
template: getTemplate
到
template: getTemplate()
虽然这可能会解决您的问题,但我建议将您的模板移动到单独的 html 文件中,而不是将其保持内联。很难调试和缩放内联 HTML.
问题代码
该指令试图在一次调用 transclude 函数中执行双重包含。
//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));
});
}
正确的代码
要将指令内容嵌入到模板中的两个位置,请调用嵌入函数两次。
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);
});
}
};
});
如果您需要新的嵌入范围,您可以使用 scope.$new()
创建它们。
var newScope = scope.$new();
transclude(newScope, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
有关创建新范围的详细信息,请参阅 AngularJS $rootScope.scope API Reference -- $new。
使用AngularJS jqLite
AngularJS jqLite 是 jQuery 的一个微型 API 兼容子集,它允许 Angular 在跨浏览器中操作 DOM兼容方式。 jqLite 仅实现最常用的功能,目标是占用空间非常小。1
jqLite 的find
方法不支持属性选择器。做
以上示例与 jqLite 兼容,使用自定义标签作为嵌入目标。
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);
});
}
};
});
这样就不需要将 jQuery 添加到应用程序作为依赖项。
我在 SO 上非常认真地询问是否可以在指令模板中两次嵌入指令的内部内容(克隆它并将其插入模板中的两个位置)。
一个非常有帮助的人帮我把这个 plunkr 放在一起。
http://plnkr.co/edit/k2UB1o4CTHtZ1voS0OKN?p=preview
一开始似乎可行。当我使用任何使用嵌入本身的子元素时,问题就来了。我得到的错误是...
[ngTransclude:orphan] 在模板中非法使用 ngTransclude 指令!找不到需要包含的父指令。元素:
例如,我有一个具有以下定义的按钮指令。
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>';
}
});
当我将其中一个按钮放入工具栏并尝试克隆它时,我收到了上述错误。
编辑:
带有完整示例的新 PLUNKR
http://plnkr.co/edit/uK8r4EA2IPRnYKfjWNVG?p=preview
如有任何帮助,我们将不胜感激。
实际错误不是来自嵌入,而是来自模板 属性。从您提供的这段代码中,您只需要做一点小改动就可以让它工作(您为模板 属性 分配了一个函数而不调用它)
来自
template: getTemplate
到
template: getTemplate()
虽然这可能会解决您的问题,但我建议将您的模板移动到单独的 html 文件中,而不是将其保持内联。很难调试和缩放内联 HTML.
问题代码
该指令试图在一次调用 transclude 函数中执行双重包含。
//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));
});
}
正确的代码
要将指令内容嵌入到模板中的两个位置,请调用嵌入函数两次。
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);
});
}
};
});
如果您需要新的嵌入范围,您可以使用 scope.$new()
创建它们。
var newScope = scope.$new();
transclude(newScope, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
有关创建新范围的详细信息,请参阅 AngularJS $rootScope.scope API Reference -- $new。
使用AngularJS jqLite
AngularJS jqLite 是 jQuery 的一个微型 API 兼容子集,它允许 Angular 在跨浏览器中操作 DOM兼容方式。 jqLite 仅实现最常用的功能,目标是占用空间非常小。1
jqLite 的find
方法不支持属性选择器。做
以上示例与 jqLite 兼容,使用自定义标签作为嵌入目标。
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);
});
}
};
});
这样就不需要将 jQuery 添加到应用程序作为依赖项。