1
votes

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...

1
Do you know the type of components projected? I mean, are you trying to implement a component like tabs which include child tab components? - Bunyamin Coskuner
I think there is more information needed to help you out. For what reason do you need to reposition the components? If they are in ContentChildren, I assume they are already defined somewhere in the template. Are the components all going to the same place? Best option would be to provide some code to get an idea... - RagnarLodbrok
I know the type yes and I even already have the components in the ContentChildren array (query)... I can loop through those components and print out properties. I just need to render it somewhere in the view like I want... - stephan.peters
The reason is that based on a given list I need to create a new list with extra components in between... - stephan.peters
I think you should read about ng-template and the use of its createEmbeddedView() method. - RagnarLodbrok

1 Answers

2
votes

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>