在模板中非法使用 ngTransclude 指令!手动执行嵌入时

Illegal use of ngTransclude directive in the template! when doing transclusion manually

本文关键字:执行 指令 ngTransclude 非法      更新时间:2023-09-26

我在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

任何帮助将不胜感激。

问题代码

该指令试图在一次调用 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));
    });
}

正确的代码

若要将指令内容嵌入到模板中的两个位置,请调用 transclusion 函数两次。

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 参考 -- $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作为依赖项添加到应用程序中。

实际错误不是来自嵌入,而是来自模板属性。从您提供的代码段中,您只需要进行一个小的更改即可使其工作(您为模板属性分配了一个函数而不调用它)

template: getTemplate 

template: getTemplate()

虽然这可能会解决您的问题,但我建议将您的模板移动到单独的 html 文件中,而不是保持内联。调试和扩展内联 HTML 非常困难。