Search code examples
angularangular2-template

How to render custom component in parent view component?


I'd like to render custom component inside mat-option. This is the code in my parent component:

  <mat-option *ngFor="let option of options" [value]="option.value">
   HERE I WOULD LIKE TO INJECT SOME COMPONENT
  </mat-option>

Let's assume that I have a component called CustomOptionView:

@Component({
    selector: 'custom-option-view',
    template: `<h1> {{ label }} </h1>`,
})
export class CustomOptionView{
@Input() label?: string;
}

And I would like to create that component manually in my child component like this:

const factory = this.componentFactoryResolver.resolveComponentFactory(CustomOptionView);

How Can I pass this instance to parent component and render it?

Why I am trying to do that? Because I would like to have options in selectlist that looks differently. One component needs to show icons and multiline text and other doesn't need it. I came to conclusion that I need a set of custom components that I could somehow inject to parent's html.


Solution

  • general API for dynamically creating a component

    You can dynamically add a component at runtime using viewContainerRef.createComponent() API

    See guide: https://angular.io/guide/dynamic-component-loader

    ready to use solution


    The above mentioned mechanism is already implemented in built in *ngComponentOutlet directive.

    See docs: https://angular.io/api/common/NgComponentOutlet

    basically, ngComponentOutlet takes the component type as a parameter.

    @Component({
      selector: 'my-app',
      template: `<ng-container *ngComponentOutlet="dynamicComponentToLoad"></ng-container>
                 <button (click)="switchComponent()">Switch components</button>`
    })
    export class AppComponent {
      // This field is necessary to expose HelloWorld to the template.
      dynamicComponentToLoad: Type<any> = Component1;
    
      switchComponent() {
         dynamicComponentToLoad = Component2;
      }
    }
    

    In you case it could look like this:

    <mat-option *ngFor="let option of options" [value]="option.value">
       <ng-container *ngComponentOutlet="option.componentType; injector:createInjector(option)"></ng-container>
    </mat-option>