0

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.

1
  • To make what possible? Commented Dec 21, 2022 at 13:16

2 Answers 2

1

You can achieve that with the compiler. Please note it is deprecated.

The Directive

import { Compiler, Directive, Input, ViewContainerRef } from '@angular/core';
import { AppModule } from './app.module';

@Directive({
  selector: '[appTemplateIterator]',
})
export class TemplateIteratorDirective<T> {
  private _data: T;
  private _selectors: string[];

  @Input()
  set appTemplateIterator(value: T) {
    this._data = value;

    this.updateView();
  }

  @Input()
  set appTemplateIteratorFor(value: string[]) {
    this._selectors = value;

    this.updateView();
  }

  constructor(
    private compiler: Compiler,
    private viewContainer: ViewContainerRef
  ) {}

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

    if (this._data && this._selectors) {
      this.compiler
        .compileModuleAndAllComponentsAsync(AppModule)
        .then((module) => {
          const allComponentFactories = module.componentFactories;
          this._selectors
            .map((selector) =>
              allComponentFactories.find(
                (componentFactory) => componentFactory.selector === selector
              )
            )
            .filter(Boolean)
            .forEach((componentFactory) => {
              this.viewContainer
                .createComponent(componentFactory)
                .setInput('data', this._data);
            });
        });
    }
  }
}

Usage

<ng-container
  *appTemplateIterator="'Foobar'; for: ['app-my-a', 'app-my-b']"
></ng-container>

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

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.