Usage Of Dynamic Component in Angular Project

Usage Of Dynamic Component in Angular Project

Hi everyone,

I would like to show you how to load a component dynamically in Angular project at runtime.

If you are working on Angular, you might know component templates are not always fixed. During the product development, you also have come across to load a component dynamically at runtime.

So let’s begin to load component dynamically.

Entry

I will show you a web page and there will be 3 buttons. These buttons will load it’s components dynamically. I have selected FrontEnd frameworks like, Angular, Vue, React.

Whichever framework button you press, that framework component will be loaded dynamically.

Define Directive

First of all, we need to define a directive like below. Because we need to tell to Angular where to put components in the UI.

import { Directive, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[framework-host]' })
export class FrameworkDirective {
    constructor(public viewContainerRef: ViewContainerRef) { }
}

This directive uses ViewContainerRef to access to view container element. We will use framework-host name that defined in @Directive clause.

Loading Component

I will show you my main app.component.ts and .html files part to load dynamically component.

html file;

<div class="card-container">
    <button (click)="loadDynamicComponentsWithIndex(0);" class="btn btn-outline-danger m-2"> <img
      width="40"
      alt="Angular Logo"
      src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
    />Angular</button>
    <button (click)="loadDynamicComponentsWithIndex(1);" class="btn btn-outline-success m-2"><img src="https://img.icons8.com/color/48/000000/vue-js.png"/>VueJS</button>
    <button (click)="loadDynamicComponentsWithIndex(2);" class="btn btn-outline-info m-2"><img src="https://img.icons8.com/color/48/000000/react-native.png"/>ReactJS</button>  
  </div>
  <!--Dynamic component area-->
  <div class="card-container">
    <ng-template framework-host></ng-template>
  </div>

We need to use &lt;ng-template to use to load dynamically component. The framework-host defined before as directive. Our dynamic component will be there.

ts file;

Before show you app.component.ts, I would like to describe other things in project.

The first one is component interface that name is FrameworkComponent. This will use to pass a data to dynamic components. This interface like below.

export interface FrameworkComponent {
  data: any;
}

The another important thing is defining FrameworkItem class to create a FrameworkComponent list.

import { Type } from '@angular/core';
export class FrameworkItem {
  constructor(public component: Type<any>, public data: any) {}
}

Dynamic components;

We have 3 components, they are AngularComponent, VueComponent, ReactComponent.

export class AngularComponent implements OnInit, FrameworkComponent{
  @Input('data') data: any;
  constructor() { }
  ngOnInit(): void {
  }
}

html;

<h2>{{data.name}} component selected</h2>
<img src="https://upload.wikimedia.org/wikipedia/commons/c/cf/Angular_full_color_logo.svg">

After above methods, I could easily explain below code. We are loading dynamic components with getFrameworkList. This method includes FrameworkItem arrays. First of all we are loading a component that index is 0 (AngularComponent).

ComponentFactoryResolver is very important to load dynamic component. Firstly, we implement as a dependency componentFactoryResolver. After injected componentFactoryResolver, we will use it in loadDynamicComponentsWithIndex method to load dynamic component like below. We access to directive's viewContainerRef and create component ref with generated by resolveComponentFactory method.

After all, you will see the dynamic component changes in the UI.

loadDynamicComponentsWithIndex(ind: any) {
    const frameworkItem = this.frameworks[ind];
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(frameworkItem.component);
    const viewContainerRef = this.frameworkHost.viewContainerRef;
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent(componentFactory);
    (<FrameworkComponent>componentRef.instance).data = frameworkItem.data;
  }

Full code of app.component.ts.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  title = 'dynamic-comp-app';
  frameworks: FrameworkItem[];
  @ViewChild(FrameworkDirective, { static: true }) frameworkHost: FrameworkDirective;
  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
  ngOnInit(): void {
    this.frameworks = this.getFrameworkList();
    this.loadDynamicComponentsWithIndex(0);
  }
  loadDynamicComponentsWithIndex(ind: any) {
    const frameworkItem = this.frameworks[ind];
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(frameworkItem.component);
    const viewContainerRef = this.frameworkHost.viewContainerRef;
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent(componentFactory);
    (<FrameworkComponent>componentRef.instance).data = frameworkItem.data;
  }
  getFrameworkList() {
    return [
      new FrameworkItem(AngularComponent, { name: 'Angular' }),
      new FrameworkItem(VueComponent, { name: 'VueJS' }),
      new FrameworkItem(ReactComponent, { name: 'ReactJS' })
    ];
  }
}

Demo show like below;

I tried to show you about loading dynamic component to your Angular project. The source code is available on github.

I hope you enjoy when reading.

Have a nice coding…

References

  1. angular.io