一尘不染

在模板中非法使用ngTransclude指令

angularjs

我有两个指令

app.directive('panel1', function ($compile) {
    return {
        restrict: "E",
        transclude: 'element',
        compile: function (element, attr, linker) {
            return function (scope, element, attr) {
                var parent = element.parent();
                linker(scope, function (clone) {
                    parent.prepend($compile( clone.children()[0])(scope));//cause error.
                  //  parent.prepend(clone);// This line remove the error but i want to access the children in my real app.
                });
            };
        }
    }
});

app.directive('panel', function ($compile) {
    return {
        restrict: "E",
        replace: true,
        transclude: true,
        template: "<div ng-transclude ></div>",
        link: function (scope, elem, attrs) {
        }
    }
});

这是我的观点:

<panel1>
    <panel>
        <input type="text" ng-model="firstName" />
    </panel>
</panel1>

错误:[ngTransclude:orphan]在模板中非法使用ngTransclude指令!找不到需要包含的父指令。元件:<div class="ng- scope" ng-transclude="">

我知道panel1不是实际的指令。但是在我的实际应用程序中,我也遇到了这个问题。

我在http://docs.angularjs.org/error/ngTransclude:orphan上看到了一些解释。但是不知道为什么我在这里有这个错误以及如何解决它。

编辑 我创建了一个jsfiddle页面。先感谢您。

编辑

In my real app panel1 does something like this:

    <panel1>
    <input type="text>
    <input type="text>
<!--other elements or directive-->
    </panel1>

结果=>

    <div>
    <div class="x"><input type="text></div>
    <div class="x"><input type="text></div>
<!--other elements or directive wrapped in div -->
    </div>

阅读 215

收藏
2020-07-04

共1个答案

一尘不染

原因是当DOM完成加载后,Angular将遍历DOM并将所有指令转换为模板, 然后再 调用compile和link函数。

这意味着,当你打电话$compile(clone.children()[0])(scope)时,clone.children()[0]这是你<panel>在这种情况下,
已经转化 的角度。 clone.children()已经成为:

<div ng-transclude="">fsafsafasdf</div>

(面板元素已被 移除和更换 )。

与您使用编译普通div相同ng-transclude。当您使用编译普通div时ng-transclude,angular会抛出异常,如文档中所述:

当您忘记设置transclude:true在某些指令定义中,然后在指令的模板中使用ngTransclude时,通常会发生此错误。

演示(检查控制台以查看输出)

即使您设置replace:false为保留<panel>,有时您也会看到转换后的元素,如下所示:

<panel class="ng-scope"><div ng-transclude=""><div ng-transclude="" class="ng-scope"><div ng-transclude="" class="ng- scope">fsafsafasdf</div></div></div></panel>

这也是有问题的,因为ng-transclude重复

演示

为避免 与角度编译过程 发生 冲突
,建议您将的内部html设置<panel1>为template或templateUrl属性

您的HTML:

<div data-ng-app="app">
        <panel1>

        </panel1>
    </div>

您的JS:

app.directive('panel1', function ($compile) {
            return {
                restrict: "E",
                template:"<panel><input type='text' ng-model='firstName'>{{firstName}}</panel>",

            }
        });

如您所见,此代码更简洁,因为我们不需要手动处理元素。

演示

更新 了不使用template或templateUrl即可动态添加元素的解决方案:

app.directive('panel1', function ($compile) {
            return {
                restrict: "E",
                template:"<div></div>",
                link : function(scope,element){
                    var html = "<panel><input type='text' ng-model='firstName'>{{firstName}}</panel>";
                    element.append(html);
                    $compile(element.contents())(scope);
                }
            }
        });

演示

如果要将其放在html页面上,请确保不要再次编译它:

演示

如果您需要为每个孩子添加一个div。只需使用开箱即用ng-transclude

app.directive('panel1', function ($compile) {
            return {
                restrict: "E",
                replace:true,
                transclude: true,
                template:"<div><div ng-transclude></div></div>" //you could adjust your template to add more nesting divs or remove 
            }
        });

演示(您可能需要根据需要调整模板,删除div或添加更多div)

根据OP更新的问题的解决方案:

app.directive('panel1', function ($compile) {
            return {
                restrict: "E",
                replace:true,
                transclude: true,
                template:"<div ng-transclude></div>",
                link: function (scope, elem, attrs) {
                    elem.children().wrap("<div>"); //Don't need to use compile here.
                   //Just wrap the children in a div, you could adjust this logic to add class to div depending on your children
                }
            }
        });

演示

2020-07-04