Dynamically Inject components in Angular
Imagine a situation where you have different notifications. you would want to show different component based on the notification type.
For instance, in LinkedIn you have different notifications templates based on the notification type: Friend update, new message, message from HeadHunter etc…
A possible solution would be to use the structural directive *ngSwitch, but imagine having dozens of different notification type. It could quickly end up with an unreadable HTML.
Introducing ComponentFactoryResolver
ComponentFactoryResolver
allows you to do just that.
All you have to do is to define an anchor point in your HTML and then you can inject into the anchor point whatever component you want.
Let’s go back to our notification example. imagine the following data set.
const notifications = [
{message: "Your Friend recommended you", notificationType: "recommendation"},
{message: "Someone tried contacting you", type: "contact"}
]
So we have 2 different type of notifications: recommendation
and contact
notification types. In this case we would need to use the RecommendationNotificationComponent
and ContactNotificationComponent
to show the appropriate template.
First, as we said we need to define an anchor point in our component’s HTML
@Component({
selector: 'app-notifications',
template: `
<h1>Dynamic templates</h1>
<ng-template #anchorPoint></ng-template>
`,
})
Now in our component we must resolve the appropriate component based on the notification type and inject it in the anchor point.
// our actual dataset
import {notifications} from "./notifications.ts"export class NotificationComponent implements OnInit {
@ViewChild('anchorPoint', { read: ViewContainerRef, static: true}) constructor(private resolver: ComponentFactoryResolver) {} ngOnInit() {
notifications.forEach(notification => {const component = this.getComponent(notification.type);
const factory = this.resolver.resolveComponentFactory(component);
this.anchorPoint.clear();
const ref = this.anchorPoint.createComponent(factory); const instance = ref.instance;
// binding the notification the component input instance.notification = notification;
} }
getComponent(notificationType: string) {
const componentsMap = {
recommendation: RecommendationNotificationComponent,
contact: ContactNotificationComponent }
return componentsMap[notificationType]; }}
So we essentially retrieved our notifications, resolved the appropriate component, clear our container and inject the component and voila.