How to get reference of Component from projected content

309 views Asked by At

I am writing a common angular library component, where the consumers can pass on optional content/template/component through angular content projection mechanism. Below are some example classes to explain better.

The hierarchy tree:

consuming-component - projects component-to-project ----->

common-container - forwards projected content to it's child ------>

common-item - projected content renders here.

Common Library:

component-to-project.component.ts - this is the component that will finally render inside common-item and is projected from the consuming component.

@Component({
  selector: 'component-to-project',
  template: '<p>Projected Successfully!</p>',
})
export class ComponentToProjectComponent { … }

common-container.component.ts - This is the intermediate component that passes on the projected content to common-item.

@Component({
  selector: 'common-container',
  templateUrl: './common-container.component.html',
  styleUrls: ['./common-container.component.scss'],
})
export class CommonContainerComponent {
    @ContentChild(TemplateRef) projectedTemplateRef!: TemplateRef<any>;
(…)
}

common-container.component.html

...

<div>
    <common-item>
        <ng-template let-context>
            <ng-container [ngTemplateOutlet]="projectedTemplateRef" [ngTemplateOutletContext]="{$implicit: context}">
            </ng-container>
        </ng-template>
    </common-item>
</div>
(…)

common-item.component.ts - This is where the projected content actually renders.

@Component({
  selector: 'common-item',
  templateUrl: './common-item.component.html',
  styleUrls: ['./common-item.component.scss'],
})
export class CommonItemComponent {
    @ContentChild(TemplateRef) projectedTemplateRef!: TemplateRef<any>;
    
    templateContext: MyContextData = { … };

    ngAfterContentInit() {
        // This is where I need the reference to the component passed through content projection.
        projectedComponent: ComponentToProject = // get component
    }
    (…)
}

common-item.component.html

(…)
<div>
    <ng-container [ngTemplateOutlet]="projectedTemplateRef" [ngTemplateOutletContext]="{$implicit: templateContext}">
    </ng-container>
</div>
(…)

Consuming Application (Common Library is added as dependency)

consuming-app.component.html

(…)
<common-container>
    <ng-template let-context>
        <component-to-project (data)="context.data"></component-to-project>
    </ng-template>
</common-container>
(…)

I want the reference to the component-to-project component inside common-item component if this is what is being projected from consuming app.

I have tried few different approaches to get the projected component reference in the common-child component but got undefined in all cases.

  • Added a reference (<component-to-project #myComponent>) to the projected component and resolve it using @ContentChild in common-item component

      @ContentChild('myComponent', { descendants: true }) 
       projectedComponent?: ComponentToProjectComponent;
    
  • Resolve it using component class as selector of @ContentChild in common-item component

      @ContentChild(ComponentToProjectComponent, { descendants: true })
       projectedComponent?: ComponentToProjectComponent;
    
  • Define an injection token for the component and use that injection token in @ContentChild to resolve.

    • component to project declaration module providers array
      { provide: TokenClass, useExisting: forwardRef(
        () => ComponentToProjectComponent).
    
    • common-child
      @ContentChild(TokenClass) projectedComponent?: 
      ComponentToProjectComponent;
    

However, none of the above approach worked.

0

There are 0 answers