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

北城以北 提交于 2019-12-08 08:00:01

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!