Reputation: 71
I have got a lot of various components, only the particular one will be displayed (which will be based on some received data from API). I want to avoid using *ngSwitch
or *ngIf
, have you got some idea how to do that? I suppose that it is something related to ng-container
or ng-template
but I really do not know how to handle this, thanks for help!
Upvotes: 2
Views: 1213
Reputation: 21
You can use this article: https://angular.io/guide/dynamic-component-loader
Here is how to map data from API to Angular components:
At my projcet I am using something like mapping templates (Component IDs from API) to angular components, and I have one component which parse JSON data to angular components by prepared map.
After fetching JSON that contains data for page (in my case it is array of modules) I put that json in one component that using *ngFor to create containers for components:
<div *ngFor="let module of page.modules"
[module]="module"
module-controller>
</div>
This module is provided by router in my case.
module-controller component is described below.
Mapping file:
const componentMap = {
123: RawHtmlComponent, // ID_FROM_API : ANGULAR_COMPONENT_CLASS
}
This config is handled at module-controller component which were used above to pass relevant components to their API IDs (templates).
ModuleControllerComponent create dynamic components from configuration and has module input to pass data from api to each component.
Every module component should have module input @Input() module: any;
ModuleControllerComponent:
@Component({
selector: '[module-controller]',
template: '<div class="module-controll" #moduleHandler></div>',
})
export class ModuleControllerComponent implements OnInit {
@Input() module: any;
@ViewChild('moduleHandler', {read: ViewContainerRef}) moduleHandler: any;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
this.setController();
}
private setController() {
const moduleComponent = componentMap[this.module.template];
if ((this.module && this.module.template && moduleComponent)) {
const factory = this.componentFactoryResolver.resolveComponentFactory(moduleComponent);
this.createComponentFromModule(factory);
}
}
private createComponentFromModule(factory) {
const cmpRef: ComponentRef<any> = this.moduleHandler.createComponent(factory);
cmpRef.instance.module = this.module; //passing api data to component
}
}
Remember to add dynamic created components to EntryComponents in your module! :)
It is very simplified version that I'm using, but idea is the same. You can extend it to sections which contains modules (now I am using sections and it's perfect) You need to create another controller - section-controller and another mapping file for sections :)
Hope I helped and sorry for my english :D
P.S. You should use other name than module it's confused with angular modules :D
Upvotes: 1
Reputation: 516
I've actually done quite a bit of this where a dynamic component needs to be loaded at runtime based on other choices/data. I found this guide from angular.io to be very helpful https://angular.io/guide/dynamic-component-loader
The magic of how this works is all in this one class ComponentFactoryResolver https://angular.io/api/core/ComponentFactoryResolver
Good luck!
Upvotes: 1