kvanbere
kvanbere

Reputation: 3352

ng-content transclude from parents scope when there are nested components

Using Angular 2/4, I have a complex page template.

Suppose I have 3 mutually nested components: page.component, inside that header.component and inside that header.title.component with custom selectors set appropriately.

page.component html template:

<layout-header></layout-header>
...

header.component html template:

<section class="dynamic-content" *ngIf="!collapsed" #dynamicContent>
  <layout-header-title></layout-header-title>
  ...
</section>

header.title.component html template:

<ng-content selector="card-layout-title"></ng-content>

Then, on my actual page template:

<layout-page>
  <card-layout-title>Title goes here</card-layout-title>
</layout-page>

The ng-content selector="card-layout-title" only works when the direct parent is the component with the tag inside to select, i.e. from header.title.component I am unable to select 2-levels-up the nested components to find the content to transclude into card-layout-title.

How can I do this (preferably without adding and passing a template ref into each level, as there are 5-10 nested components at each level)?

Upvotes: 3

Views: 3938

Answers (2)

kvanbere
kvanbere

Reputation: 3352

I split this additional information out from the answer by @dohpaz42 as it's a lot less relevant to the general use-case.

If your heirarchy is not completely flat i.e.

<layout-dyn-page>
  <layout-header>
    <layout-title>Title</layout-title>
    <layout-summary>Summary</layout-summary>
  <layout-header>
</layout-dyn-page>

the solution above will not work as ng-content select= does not select elements that aren't in the top level. When you try and project them downwards, you project them with their wrapping tag no matter how you try, so currently selecting elements nested within by tag seems impossible. You must flatten it i.e.

<layout-dyn-page>
  <layout-title>Title</layout-title>
  <layout-summary>Summary</layout-summary>
</layout-dyn-page>

This could very well be a bug (or missing feature) in angular, but for now (without documentation) we can't know.

Upvotes: 6

dohpaz42
dohpaz42

Reputation: 528

First, it's <ng-content select=".card-layout-title"></ng-content> and not <ng-content selector=".card-layout-title"></ng-content>; easy mistake to make, given the lack of documentation.

It seems, from my testing, that using Transclusion in Angular 2/4 replaces the top-level content first, so that by the time it gets down to the ng-content selector, the .card-layout-title element no longer exists. So, I propose that a solution to this problem be that you "walk" the top-level content down the chain with nested ng-content elements. Plunker

Upvotes: 4

Related Questions