Home > Software engineering >  Angular Use Component By Selector Array
Angular Use Component By Selector Array

Time:12-22

Is there a way to make this possible in angular?

const arrayOfComponents = ['app-component-1', 'app-component-2', 'app-component-3']

<ng-container *ngFor="let component of arrayOfComponents">
<{{ component }} [data]="data"></{{ component }}>
</ng-container>

instead of:

<app-component-1 [data]="data"></app-component-1>
<app-component-2 [data]="data"></app-component-2>
<app-component-3 [data]="data"></app-component-3>

Because sometime we don't know the name of the component to view and the name is sent programmatically.

In other words I am trying to make a generic component which I send an array of component names/selectors to it and it renders them.

CodePudding user response:

You can achieve something simelar with a custom structural directive.

The Directive

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

interface IteratorContext<T> {
  appTemplateIterator: T;
  $implicit: T;
}

@Directive({
  selector: '[appTemplateIterator]',
})
export class TemplateIteratorDirective<T> {
  private context: IteratorContext<T> = {
    appTemplateIterator: undefined,
    $implicit: undefined,
  };

  private _templates: TemplateRef<IteratorContext<T>>[];

  @Input()
  set appTemplateIterator(value: T) {
    this.context.appTemplateIterator = value;
    this.context.$implicit = value;

    this.updateView();
  }

  @Input()
  set appTemplateIteratorFor(value: TemplateRef<IteratorContext<T>>[]) {
    this._templates = value;

    this.updateView();
  }

  constructor(private viewContainer: ViewContainerRef) {}

  updateView() {
    this.viewContainer.clear();

    if (this.context.appTemplateIterator && this._templates) {
      this._templates.forEach((template) =>
        this.viewContainer.createEmbeddedView(template, this.context)
      );
    }
  }
}

Usage

<ng-container
  *appTemplateIterator="'Foobar'; for: [first, second]"
></ng-container>

<ng-template #first let-data>
  <app-my-a [data]="data"></app-my-a>
</ng-template>

<ng-template #second let-data>
  <app-my-b [data]="data"></app-my-b>
</ng-template>

Stackblitz: https://stackblitz.com/edit/angular-ivy-gbzkm4?file=src/app/app.component.html

CodePudding user response:

You can not use interpolation in place for HTML tags. Your best bet would be the Dynamic Component Loader

  • Related