ng-transclude on element with transclusion

70 views
Skip to first unread message

Cj de Vos

unread,
Aug 7, 2015, 4:54:16 AM8/7/15
to AngularJS
I don't understand why the following scenario does not work. Please can someone explain the issue to me?

Scenario: 2 directives, both have transclude: true, 1 has a template with the other directives and the ng-transclude directive. This situation doesn't render the expected result. Using ng-transclude on another element fixes the issue, but doesn't make my DOM look really nice.


.directive("testTranscludeInner", function () {
    return {
        restrict: "E",
        transclude: true,
        scope: true,
        template: "<div><hr />1: <div ng-transclude></div></hr /></div>",
        link: function (scope, el, attrs) {
            scope.name = "TRANSCLUDE1";
        }
    }
})
.directive("testTranscludeOuter", function () {
    return {
        restrict: "E",
        transclude: true,
        scope: true,
        template: "<div><hr />2: <test-transclude-inner ng-transclude></test-transclude-inner></hr /></div>",
        link: function(scope, el, attrs) {
            scope.name = "TRANSCLUDE2";
        }
    }
})

and the following HTML

<test-transclude-outer><p>This data should be visible</p></test-transclude-outer>

Result: does not render the expected result. 

If instead the template of testTranscludeOuter is as follows, it does work.
        template: "<div><hr />2: <test-transclude-inner><div ng-transclude></div></test-transclude-inner></hr /></div>",

Looking forward to the reason why it does not work....


Best regards,
CJ de Vos.


Stewart Mckinney

unread,
Aug 8, 2015, 12:08:00 PM8/8/15
to ang...@googlegroups.com
It's pretty straightforward once you understand the sometimes-tricky transclude.

ng-transclude basically just calls "element.append( transclude() )" in it's linking function, which basically just adds the transcluded content to the element that asks for it. 

The way translcude() works is it looks up its parent chain and finds the first element that defines 'transclude:true'. Transclude() then returns that content.

In your first example, ng-transclude is defined on your inner element " <test-transclude-inner ng-transclude>". When angular compiles your outer element it sees this as the following:

-> test-transclude( new scope, transclude )
 -> ng-transclude

And normally thats what you want!

But if you look carefully at  <test-transclude-inner ng-transclude></test-transclude>, you will see that there is no transcluded content. ( Between the <>, there is no HTML! ). 

Look now at <div><hr />2: <test-transclude-inner><div ng-transclude></div></test-transclude-inner></hr /></div>.

You will see that inside <test-transclude-inner>, you now have the <ng-transclude>. "ng-transclude" is now transcluded content. When your inner directive compiles, your "ng-transclude" in your inner directive will be replaced by "ng-transclude" from your outer directive. The ng-transclude directive will then correctly look up to its parent and transclude your intended content.

Hope that helps!

(transclude is a thing)


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages