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

拥有回忆 提交于 2019-12-06 22:11:35

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.

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.

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