Loading Component dynamically in Angular

In this tutorial, we shall see how to dynamically switch between two components inside a template in angular.

Create an angular project

First, lets create an angular application using the following angular cli command.

ng new angular-dynamic-components

Create Components in the angular project

Next, lets create two components. One will the HomeComponent and the other one will be ContactComponent.

ng g c home
ng g c contact

Create a service to query components by name

Next, we shall create a service which will hold the reference to these components. Create a service using the following angular cli command.

ng g s services/component-instance

Next, open the ComponentInstanceService and modify the code as below.

import { Injectable } from '@angular/core';
import { HomeComponent } from '../home/home.component';
import { ContactComponent } from '../contact/contact.component';

@Injectable({
  providedIn: 'root'
})
export class ComponentInstanceService {

  componentInstances: Map<string, any> = new Map();

  constructor() {
    this.setComponent('home', HomeComponent);
    this.setComponent('contact', ContactComponent);
  }
  setComponent(name: string, component: any): void {
    this.componentInstances.set(name, component);
  }

  getComponent(name: string) {
    return this.componentInstances.get(name);
  }
}

Here, we have imported the two components. Then we have created a variable componentInstances of type Map. This service will contain two functions setComponent() and getComponent() function.

The setComponent() function takes 2 arguments. The first argument is the string and the second argument is the Component. Then we will set the Component with name as the key to the Map variable componentInstances.

The getComponent() function which gets the key as parameter and returns the Component associated with it.

In the constructor of the service we will add the HomeComponent with home as its key and ContactComponent with contact as the key by calling the setComponent() function.

Add FormsModule to AppModule

Next, open the app.module.ts file and add the reference to the FormsModule and add it the the imports array. Also add the HomeComponent and ContactComponent to the entryComponents array.

import { BrowserModule, HammerModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './angular-material/angular-material.module';
import { HomeComponent } from './home/home.component';
import { ContactComponent } from './contact/contact.component';
@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    ContactComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    BrowserAnimationsModule,
    AngularMaterialModule,
    HammerModule
  ],
  providers: [],
  entryComponents: [HomeComponent, ContactComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

Next, Open the app.component.html file and modify the code as below.

<select [(ngModel)]='componentName' (change)='loadComponent(componentName)'>
  <option value='home'>Home</option>
  <option value='contact'>Contact</option>
</select>
<ng-template #mainContent>
</ng-template>

Here, we have a dropdown which holds two values Home and Contact which is binded to the Model componentName on selecting any value. We also have a ng-template with the name mainContent to which the components will be replaced depending on the value selected in the dropdown.

Update AppComponent to load components dynamically

Now open the app.component.ts file and modify the code as below.

import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { ComponentInstanceService } from './services/component-instance.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  componentName: string;
  @ViewChild('mainContent', { read: ViewContainerRef, static: true }) mainContent: ViewContainerRef;
  constructor(private componentInstance: ComponentInstanceService, private resolver: ComponentFactoryResolver) { }
  ngOnInit(): void {

  }

  loadComponent(name: string) {
    console.log('Function has been called', name);
    this.mainContent.clear();
    const component = this.componentInstance.getComponent(name);
    const componentFactory = this.resolver.resolveComponentFactory(component);
    this.mainContent.createComponent(componentFactory);
  }
}

The ViewChild we will refer the template as the ViewContainerRef.

Inject the ComponentInstanceService and ComponentFactoryResolver to the constructor.

Everytime when the dropdown is changed we will call the loadComponent with its name. Now we pass the name which is the key to the getComponent() function and get the Component associated with it.

Then, the ComponentFactoryResolver is used to resolve a ComponentFactory for the specific component. Then to add the component to the template, you call createComponent() on ViewContainerRef.

Run the angular project

Now, run your application with the following command.

ng serve --o

Most Read