Search code examples
angularangular-componentsangular-template

Construct component selector via an @Input


How does one construct a selector programmatically in Angular?

Let's say I have a parent component called header.component which looks like this;

export class ContentHeaderComponent {
  @Input() iconName: string;
}

...and I am using Angular Feather to add icons to the application which requires you to do the following to create an icon:

<i-chevron-down></i-chevron-down>

In my header component template I want to pass "chevron-down" to the tag via a parent component. In effect I am looking to do something like this in the header component:

<i-{{ iconName }}></i-{{ iconName }}>

Is constructing a selector on the fly possible in Angular?


Solution

  • Your use case would be really simple if you were using a css or ligature based approach, but because your library has 1 comp per icon and there is basically no common interface among them, AFAIK there is virtually no way to map a string to its correspondent component class.

    The approach suggested in the comments wont work, as angular will not create component instances from sanitized HTML.

    You could try the following idea: instead of passing the icon name, you could pass a template with the desired icon and embed it in the component. This can be done as follows:

    @Component({
      selector: 'foo-header'
    })
    export class ContentHeaderComponent {
      @Input() iconTemplate: TemplateRef<any>;
    }
    

    content-header.component.html

    <ng-container *ngIf="iconTemplate">
      <ng-container [ngTemplateOutlet]="iconTemplate"></ng-container>
    </ng-container>
    

    foo.component.html

    <foo-header [iconTemplate]="iconRef"></foo-header>
    <ng-template #iconRef>
      <i-chevron-down></i-foo-icon>
    </ng-template>
    

    Another approach would be to directly transclude the icon markup into the component:

    @Component({
      selector: 'foo-header'
    })
    export class ContentHeaderComponent {}
    

    content-header.component.html

    <ng-content select="[header-icon]"></ng-content>
    

    foo.component.html

    <foo-header>
      <i-chevron-down header-icon></i-foo-icon>
    </foo-header>
    

    You can read about these approaches and their pros/cons in this article.