Dynamic components in Angular 8

Dynamic components in Angular 8

The dynamic component is one of the versatile and core concept introduced in Angular, Component template is not fixed. An application needs to load new elements at runtime in various scenarios.

The dynamic component is the component which is created dynamically at the runtime. Angular has its API for loading components dynamically.

Dynamic component loading

In the given example, we can see how to build a dynamic ad-banner.

The hero agency is planning an ad-campaign with several different ads cycling through the banner, where new ad components are added often by different teams. We need to load a new component without a fixed reference to the component in the ad banner's template.

Angular comes with its API for loading components dynamically.

Steps required to create Dynamic Component in Angular 8

  1. Create an anchor directive
  2. Loading components
  3. Resolving components
create Dynamic Component in Angular 8

Create an Anchor Directive

We should know where to include this anchor point into components. Create helper directive called NewsFeedDirective to create the anchor to insert anywhere to the component. The ad banner uses a directive called AdDirective to make a valid insertion point in the template bar.

src/app/ad.directive.ts

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

AdDirective injects ViewContainerRef to access to the view container of the element that host the dynamic added component.

In the @Directive decorator, observe the selector name, ad-host; that is, we use to apply the directive in the element.

Loading Components

Most of the ad banner implemented in ad-banner.component.ts. To keep things simple in the example, the HTML is in the @Component decorator’s template properly as a template string.

The <ng-template> element is where we apply the directive we just made. To ask the AdDirective, recall the selector from ad.directive.ts and ad-host. Apply the <ng-template> without the square brackets.

src/app/ad-banner.component.ts(template)

template: `
  

Advertisements

`

The <ng-template> element is good choice for dynamic component because it doesn't render any additional output.

Resolving components

In Resolving component, AdBannerComponent takes an array of AdItem objects as input, which finally comes from the AdService. AdItem objects generate the type of component to load and any data to bind in the component.AdService returns the actual ad making up the ad campaign.

Passing an array of a component to AdbannerComponent allows for a dynamic list of ads without static element in the template.

src/app/ad-banner.component.ts(excerpt)

export class AdBannerComponent implements OnInit, OnDestroy {
@Input() ads: AdItem[];
currentAdIndex = -1;
@ViewChild(AdDirective, {static: true}) 
adHost: AdDirective;
interval: any;
constructor (privatecomponentFactoryResolver: ComponentFactoryResolver)
{}
ngOnInit() {
this.loadComponent();
this.getAds(); 
}
ngOnDestroy(){
clearInterval(this.interval);
}
loadComponent(){ 
this.currentAdIndex=
(this.currentAdIndex + 1) % this.ads.length;
const adItem = this.ads[this.currentAdIndex];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
}
getAds() { 
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
} 

After loadComponent() select an ad, it uses ComponentFactoryResolver to resolve a ComponentFactory for each particular component. The ComponentFactory creates an instance of each component.

Next, we are targeting the viewContainerRef that exists on this specific instance of the component. Because it’s referring to adHost is the directive we set up earlier to tell Angular that where to insert dynamic components.

As we may recall, AdDirective injects ViewContainerRef into its constructor. The directive accesses the element that we want to use to host the dynamic component.

To add the component in the template, we can call createComponent() on the ViewContainerRef.

The createComponent () method returns a reference into the loaded component. Use the reference to interact with the component by assigning to its properties or calling its methods.

Selector References

The Angular compiler generates a ComponentFactory for a  component referenced in a template. There are no selector references in a template. There are no selector references in the template for dynamically loaded components since they are load at the runtime.

To ensure that the compiler quiet generates a factory, add dynamically loaded components into the NgModule’s entryComponents array:

entryComponents: [ HeroJobAdComponent,HeroProfileComponent],

The AdComponent interface

In the ad-banner, all components implement a common AdComponent interface to standardize the API for passing data to the component.

hero-job-ad.component.ts

import { Component, Input } from '@angular/core';
import { AdComponent }from './ad.component';
@Component({
template: `
<div class="job-ad">
<h4>{{data.headline}}</h4>
{{data.body}}
</div>
   `
}) 
export class HeroJobAdComponent implements AdComponent {
@Input() data: any;
} 

Output Final ad banner

It is changing in per 5 seconds so that I put all the screenshot here serially. All the screenshot came one by one like an ad-banner.

Featured hero profile
Brave as they come
Opening in all departments
Hiring for Several position