How to make nested transclusion in angular work?
Asked Answered
R

2

7

I cannot make nested transclusion work.

There are two directives, both of which declare they will transclude their content. When I nest them, the inner doesn't have any content.

Here is this fiddle, that demonstrates my problem.

Here is the code:

function Ctrl($scope) {
  $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
}

angular.module('transclude', [])
 .directive('outer', function(){
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      scope: {},
      template: '<div style="border: 1px solid black;">' +
                '<div>Outer</div>' +
                '<inner ng-transclude></inner>' +
                '</div>'
    };
 }).directive('inner', function(){
     return {
         restrict: 'E',
         transclude: true,
         replace: true,
         template :'<div style="border: 1px solid red;">' +
                   '<div>Inner</div>' +
                   '<div ng-transclude></div>' +
                   '</div>'
     };
 });
Retrace answered 17/10, 2013 at 15:17 Comment(0)
S
9

You should ng-transculde inside the inner directive since transclude replaces the inner html

angular.module('transclude', []).directive('outer', function(){
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<div style="border: 1px solid black;">' +
            '<div>Outer</div>' +
            '<inner><div ng-transclude></div></inner>' +
            '</div>'
        };
});

No change to inner directive needed.

I have updated the fiddle here

Selfpropelled answered 17/10, 2013 at 17:27 Comment(4)
Thanks. Now it seems obvious. :)Retrace
One thing to note is that this approach adds extra markup which, if you're doing a deep nesting, can get a bit messy. transclude:element avoids that. But for your use either is probably good.Lhasa
@Lhasa If we remove this extra markup inner html of outer div would not get transcluded whether you use transclude:element. Let me know if I am wrong. Thanks :)Selfpropelled
Yea, oops- I was thinking about a rather more complex and different scenario I had just been looking at. For your situation, you're right.Lhasa
U
0

Another way to do this, which can be useful in self contained components is displayed in this JSFiddle

.directive('outer', function(){
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      template: '<div style="border: 1px solid black;">' +
                '<div>Outer</div>' +
                '<inner></inner>' +
                '</div>'
    };
 })
.directive('inner', function(){
     return {
         restrict: 'E',
         replace: true,
         require: '^outer',
         template :'<div style="border: 1px solid red;">' +
                   '<div>Inner</div>' +
                   '<div ng-transclude></div>' +
                   '</div>'
     };
 });

This will pass the transclude: true down the dom tree to the inner directive.

The downside of this is that the cannot be used by itself and in the jsfiddle it throws an ngTransclude: Orphan Directive Error

Because of this I require that the inner directive be a child of the outer directive, that way it will always have the transclusion passed down to it.

This is really nice to break up large directives into smaller ones.

Underrate answered 3/5, 2016 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.