To allow customer customization, I need a way to load component dynamically using a string, taken from backend.
I see this usefull guide: https://medium.com/angular-in-depth/loading-components-dynamically-in-angular-cd13b9fdb715
but, as other tutorial like the official one, they always assume you already know classnames.
Look at this code from the tutorial:
async loadComponent(vcr: ViewContainerRef, isLoggedIn: boolean) {
const { GuestCardComponent } = await import('./guest-card/guest-card.component');
const { UserCardComponent } = await import('./user-card/user-card.component');
...
The string inside import is not a problem but the definition of class is.
I need a placeholder in my template for loading a component I know I have in the FileSystem but I don't know its name.
Something like this:
From backend i get:
var dynamic_loading_component = { "classname" : "AdidasCardComponent" , "path" : "/components/adidas.component" }
then I would like to use like this:
const { dynamic_loading_component["classname"] } = await import(dynamic_loading_component["path"]);
vcr.clear();
let component : any = dynamic_loading_component["classname"];
return vcr.createComponent(this.cfr.resolveComponentFactory(component))
Some sort of Reflection.
Is it possible?
I finally found a way merging some other posts. Its the best I could get.
In the page where you have to dynamic load component, have this:
@ViewChild(PlaceHolderDirective, { static: true })
placeholderHost: PlaceHolderDirective;
...
ngAfterViewInit()
{
const viewContainerRef = this.placeholderHost.viewContainerRef;
var component_data = { "classname" : "ExampleComponent" }; //this is an example
this._componentLoader.loadComponent(viewContainerRef, {} );
}
PlaceHolderDirective is:
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[component-placeholder]' })
export class PlaceHolderDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
Now, create a Service for loading component dynamically:
import { Injectable,ComponentFactoryResolver, ViewContainerRef, NgModuleFactoryLoader, Injector, Type } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ComponentLoaderService
{
constructor(
private cfr : ComponentFactoryResolver)
{
//constructor
}
async loadComponent(vcr: ViewContainerRef, component_data = {} )
{
vcr.clear();
const factories = this.cfr['ngModule']['instance']['__proto__']['constructor']['__annotations__'][0]['declarations'];
var factoryClass = <Type<any>>factories.find((x: any) => x.name === component_data["classname"] );
const factory = this.cfr.resolveComponentFactory(factoryClass);
return vcr.createComponent(factory);
}
}
You still have to register your component in app.module but its the only section you need to write.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With