Search code examples
angularangular13ng-templateng-contentangular-content-projection

content project elements through directive and <ng-template> in angular 13


I have the following scenario:

page.component.html

<app-component-w-directive>
  <child-component></child-component>
</app-component-w-directive>

component-w-directive.component.html

<ng-template
  myCustomDirective
  [someInputs]="someValues"
  [someInputs]="someValues"
  [someInputs]="someValues"
>
  <!-- my failed attempt -->
  <ng-content></ng-content>
</ng-template>

I use the component-w-directive component to cast different components dinamically depending on some information, and I want them all to share the same <child-component> from page.component.html.

Currently, within component-w-directive.component I have full access to <child-component>. And tried to do the following to drill the ng-content down to one of the components generated dinamically with the directive with no success, in any of the "cast-able" components, its undefined the ng-content.

casted-from-directive.component.html

<!-- some html -->

  <ng-content></ng-content>
  <!-- (expected to be the child-component from page.component.html) -->

<!-- some html -->

How can I project the <child-component> in the dynamic generated ones through the directive?

EDIT: here's an example https://stackblitz.com/edit/angular-ivy-qgbslk


Solution

  • I did not find an elegant way for any component, so it will work only when you have an access to injected components (Today, Tomorrow)

    1. you need to change this components as well as MyComponent interface TodayComponent HTML:
    <ng-container *ngTemplateOutlet="content"></ng-container>
    

    TodayComponent.ts

    content?: TemplateRef<any>;
    
    1. Now we need to add same input to creating directive and pass it to the creating component
     @Input() contentTemplate: TemplateRef<any>;
    ...
    
      this.cmpRef = this.viewContainerRef.createComponent<MyComponent>(component);
      this.cmpRef.instance.content = this.contentTemplate;
    
    1. Final step is to make a bridge between Hook component and directive. Notice that we need to wrap ng-content into ng-template and pass it as ref to the creating directive.
    <ng-container
      appDynamicComponent
      [compSelector]="compSelector"
      [color]="color"
      [contentTemplate]="content"
    ></ng-container>
    
    <ng-template #content>
      <ng-content></ng-content>
    </ng-template>
    
    1. Working sample

    HTML