Dynamic Component:

Sanjay K
YavarTechWorks

--

→ Dynamic components are components which we create dynamically at run-time.
→ For example, a dynamic component can be a modal, alert, pop-ups, advertisement cards that keep changing in a webpage etc..
→ The components that we load programmatically are called as dynamic components.

ngIf vs Dynamic Components:

→ ngIf is a structural directive that angular provides us to conditionally render an element in the HTML template.
→ Using ngIf and dynamic components will look similar in terms of usage. But dynamic components has way more advantages and features than ngIf. → For example, consider we have 3 components named Advertisement1, Advertisement2 and Advertisement3. We need to conditionally render any one of the component. Here we can use ngIf for these three component’s selector in the HTML.

<app-Advertisement1 *ngIf="canLoadFirst"></app-Advertisement1>
<app-Advertisement2 *ngIf="canLoadSecond"></app-Advertisement2>
<app-Advertisement3 *ngIf="canLoadThird"></app-Advertisement3>

Here the problem is, when we use multiple ngIf’s, it leads to performance issues and also the code becomes messy if we have more number of elements to conditionally render. So ngIf is not the best option to choose here.

→ In scenarios like this, we can use dynamic component loading, which is a better approach.

Creating a dynamic component:

// dynamic-component-directive.ts

import { Directive, ViewContainerRef } from "@angular/core";

@Directive({
selector:'[loadHostHere]'
})
export class DynamicComponentDirective{
constructor(public viewContainerRef: ViewContainerRef){}
}

First we are creating a directive and giving it a selector name as [loadHostHere]. We are using the square-brackets since we need this selector to be a attribute-selector.
Then we are injecting the ViewContainerRef to a public property in the constructor to use this in other components.
Also, we need to a add this directive in the declarations array of the module we are working in and we need to export it.

Now we need to create the component that we want to load dynamically.

Here we created the alert-modal component template.

And this is the TS file of the alert-modal component.
This component has receives a data as input and emits a event as output when the close button is clicked.
So overall, this is a simple modal component.

Now we will see how to load this component programmatically anywhere in the application. Here we are taking home-page component as an example to load the alert modal component inside the home-page component.

// home-page.component.html

<div class="p-5">
<h4>Click the button to load the dynamic component</h4>
<button (click)="loadComponent()" class="btn btn-success mt-4">Click</button>
<ng-template loadHostHere></ng-template>
</div>

Here in this HTML file, we are having a button to load the dynamic component and we are using ng-template to mark the place for the dynamic component to render. In the ng-template directive we are using the attribute selector (loadHostHere) of the directive that we have created.

// home-page.component.ts

import { Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { AlertModalComponent } from 'src/app/shared/components/alert-modal/alert-modal.component';
import { DynamicComponentDirective } from 'src/app/shared/directives/dynamic-component.directive';

@Component({
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
})
export class LoginComponent implements OnInit {
constructor() {}
@ViewChild(DynamicComponentDirective, { static: true })
alertModalHost!: DynamicComponentDirective;
vcr!: ViewContainerRef;

ngOnInit() {
this.vcr = this.alertModalHost.viewContainerRef;
}

loadComponent(): void {
this.vcr.clear();
const componentRef = this.vcr.createComponent(AlertModalComponent);
componentRef.instance.data =
'This is the data passed while creating the component dynamically';
componentRef.instance.closeModal.subscribe(() => {
this.closeModal();
});
}

closeModal() {
this.vcr.clear();
}
}

Here in the home-page.component.ts, we are using a @ViewChild decorator to inject the reference of the element. The first argument is the directive that we need to inject (DynamicComponentDirective) and second argument is a configuration and we are declaring a property named alertModalHost and mentioned its type as the DynamicComponentDirective.

In the ngOnInit method we are assigning the viewContainerRef (a public property that we have declared in the directive) to a local property vcr.

Now, when the user clicks the button in the home-component the loadComponent method will be triggered and we are clearing the vcr to clear the components if we already have loaded any dynamic component.
And we are creating the dynamic component using createComponent method and we are passing the AlertModalComponent as the argument.

Also, we are passing an input to the AlertModalComponent named data which we can access using the instance.

The AlertModalComponent also has an output (event emitter) which will be triggered when we click the close button in the AlertModalComponent. We are subscribing to this event in the home-component.ts using instance.closeModal which is the name of the event emitted and we are clearing the vcr once the user clicks the close button.

Likewise, we can perform some complex logic, load a specific component among an array of components based on the logic etc..

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

So this is how the output looks like. When we click the ‘click’ button, the dynamic component alert-modal is created and it has a close button and if we click the close button an event is emitted and it is subscribed in the home component where the viewContainerRef is cleared and the alert-modal component vanishes away.

This is a simple example for dynamic components. This will be very useful in scenarios like, when we need to randomly show some component from an array of components using setInterval, or load a component from an array of components based on some specific logic etc..

--

--