The above answer gets the job done but just like with any other switch case you will need to keep on adding more switch conditions for each type. Like talha mentioned in the comments it might be better to use dynamic component rendering. Although this solution requires more configuration but it should be easier to manage in the long run.
Essentially something like this. heres the working stackblitz link.
const datas = [
{type: 'CustomA', id: 1, label: 'foo'},
{type: 'CustomB', src: './images/some.jpg'}
{type: 'CustomX', firstName: 'Bob', secondName:'Smith'}
]
import AComponent from 'wherever';
import BComponent from 'wherever';
import XComponent from 'wherever';
// constants file
export const TypeMappedComponents = {
CustomA: AComponent,
CustomB: BComponent,
CustomX: XComponent
}
// dynamic-renderer.component.html
<ng-template appRenderDynamically></ng-template>
//dynamic-renderer.component.ts
import { TypeMappedComponents } from '../constants';
import { RenderDynamicallyDirective } from '../render-dynamically.directive';
@Component(...all the decorator stuff)
export class DynamicRendererComponent {
_data: Record<string, unknown> = {};
componentType = '';
@Input() set data(data: Record<string, unknown>) {
this._data = data;
this.componentType = data.type as string;
this.componentType && this.createDynamicComponent(this.componentType);
}
@ViewChild(RenderDynamicallyDirective, { static: true })
renderDynamic: RenderDynamicallyDirective;
constructor(private cfr: ComponentFactoryResolver) {}
createDynamicComponent(type: string) {
const component = this.cfr.resolveComponentFactory(
TypeMappedComponents[type]
);
this.renderDynamic.vcr.clear();
const componentRef = this.renderDynamic.vcr.createComponent(
component
) as any;
componentRef.instance.data = this._data;
}
}
and then you just loop it and pass the data to dynamic-renderer. This should dynamically create the component according to the type.
<ng-container *ngFor="let data of datas">
<app-dynamic-renderer [data]="data"></app-dynamic-renderer>
</ng-container>
Heres the renderDynamicallyDirective
which places the component into the view.
@Directive({
selector: '[appRenderDynamically]'
})
export class RenderDynamicallyDirective {
constructor(public vcr: ViewContainerRef) { }
}
Although this code is longer than the switch case, its more of a one time effort. Since if you have a new type and new component to go along with it you just need to created the required component. then add the new type and the component associated with it to the TypeMappedComponent
.