동적으로 컴포넌트 불러오기
동적으로 컴포넌트를 불러오는 내용으로서 angular 14 미만 버전에서 사용되는 내용입니다.
angular14 이상에서는 ReflectiveInjector, ComponentFactoryResolver 를 사용할 수 없으므로 다음장에서 다시 다루겠습니다.
import {
Component,
NgModule,
Inject,
ViewChild,
ViewContainerRef,
ReflectiveInjector,
ComponentFactoryResolver,
AfterViewInit} from '@angular/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Component1 } from './component1';
import { Component2 } from './component2';
@Component({
selector: 'app-modal-dynamic',
template: `
<ng-template #container></ng-template>
`
})
export class DynamicComponent implements AfterViewInit {
@ViewChild('container', {read: ViewContainerRef, static: true}) private container?: ViewContainerRef;
private componentData: any;
constructor(
private dialogRef: MatDialogRef<FairnessComponent>,
@Inject(MAT_DIALOG_DATA) public data: { title: string },
private resolver: ComponentFactoryResolver,
) {
}
public ngAfterViewInit(): void {
setTimeout(() => { this.create(); }, 1);
}
public create(): void {
switch (this.data.title) {
case 'Component1':
this.componentData = {
component: Component1,
inputs: { data: this.data}
};
break;
case 'Component2':
this.componentData = {
component: Component2,
inputs: { data: this.data}
};
break;
}
if (!this.componentData || !this.componentData.component) {
return;
}
// Inputs need to be in the following format to be resolved properly
const inputProviders = Object.keys(this.componentData.inputs).map((inputName) => {
return { provide: inputName, useValue: this.componentData.inputs[inputName] };
});
const resolvedInputs = ReflectiveInjector.resolve(inputProviders);
// We create an injector out of the data we want to pass down and this components injector
if (this.container) {
const injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.container.parentInjector);
// We create a factory out of the component we want to create
const factory = this.resolver.resolveComponentFactory(this.componentData.component);
// We create the component using the factory and the injector
const component = factory.create(injector) as any; // as any type으로 형을 선언해 주어야 component.instance.popclosed 에서 에러가 발생하지 않음
this.container.insert(component.hostView, 0);
// 컴포넌트의 액션을 리스닝 한다.
component.instance.popclosed.subscribe(() => {
component.destroy();
this.dialogRef.close();
});
}
}
}
@NgModule({
declarations: [
Component1,
Component2
],
imports: [
..........
],
exports: [
Component1
]
})
export class DynamicComponentModule { }