stephan.peters
stephan.peters

Reputation: 1107

render component passed through @ContentChildren or @ContentChild

I'm doing content projection with @ContentChildren.

Now I have the need to put the components from the contentchildren query somewhere where I choose it to be. I also have to add an extra divider if not the last one in the array. So the reason is that based on a given list of components (content children) I need to create a new list with extra components in between...

How can this be done in Angular? I looked up for dynamic component injection but it's always starting from a component type being used to render a component. But in this case I already have the components in the ContentChildren query array...

Upvotes: 1

Views: 2712

Answers (1)

Bunyamin Coskuner
Bunyamin Coskuner

Reputation: 8859

Here is working solution

To simulate what you want to implement, I've implemented two components, tabs and tab

You can use these components as follows

<my-tabs>
  <my-tab text="Tab 1"></my-tab>
  <my-tab text="Tab 2"></my-tab>
  <my-tab text="Tab 3"></my-tab>
</my-tabs>

<div>------------------</div>

<my-tab text="This is rendered itself" [single]="true"></my-tab>

Within TabComponent, I've wrapped ng-content with ng-template so that I can inject it within component with @ViewChild(TemplateRef) content.

@Component({
  selector: 'my-tab',
  template: `
    <ng-template>
      {{text}}
    </ng-template>

    <ng-container *ngIf="single">
      <ng-container *ngTemplateOutlet="content"></ng-container>
    </ng-container>
  `
})
export class TabComponent {
  @ViewChild(TemplateRef) content;

  @Input() text;
  @Input() single = false; // this will allow to use this component on its own
}

TabsComponent

@Component({
  selector: 'my-tabs',
  template: `
    <div *ngFor="let tab of tabs; let isLast = last">
      <ng-container *ngTemplateOutlet="tab.content"></ng-container>
      <hr *ngIf="!isLast">
    </div>
  `,
})
export class TabsComponent  {
  @ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
}

You can use tab.content within *ngTemplateOutlet directive.

<ng-container *ngTemplateOutlet="tab.content"></ng-container>

Upvotes: 3

Related Questions