Angular – 通过提交表单将一个组件的新实例添加到显示中,动态加载同一组件的多个实例

Angular – Dynamically load multiple instances of the same component by submitting a form to add a new instance of a component to the display

问题

我正在尝试动态加载同一组件的多个实例,当用户提交表单时,新组件 added/loaded 会出现在屏幕上。这背后的想法是,用户可以提供有关表单的详细信息,然后显示在创建的该组件的特定实例上。

我最初的想法是拥有某种数据结构,例如键对值的数组或映射,这样当用户提交形式。然后 angular 可以以某种方式显示驻留在数据结构中的组件的每个实例,如下图所示:

需要注意的是,表单实际上是它自己的独立组件,以模态对话框的形式存在。当按下绿色 添加状态框 按钮时,将打开此表单对话框,然后用户可以提交表单并(希望)能够使用从提交的表格中提供的数据。

然而这被证明是困难的,目前我在上面的屏幕截图中实现这一点的方法是仅在 app.component.html 中单独显示每个组件,这是根本不是动态的,没有用户控制:

<app-header></app-header>
<div class='status-box-container'>
    <app-status-box></app-status-box> //component I’m trying to display
    <app-status-box></app-status-box> //component I’m trying to display
    <app-status-box></app-status-box> //component I’m trying to display
</div>

我尝试过的事情

我已经学习了一些教程,但要么是上述教程的结果不能完全满足我的要求,要么根本不起作用,要么太复杂,我无法理解。

首先我尝试遵循 this official guide from the Angular website 但这一次只显示一个组件并且每 3 秒动态更改其内容而不是同时显示一个组件的多个实例。

接下来,我尝试了follow this stackblitz from ,但是我发现这个不行,而且非常复杂,其中大部分我都看不懂。虽然它非常接近我想要实现的目标。

最后,我尝试遵循 this stackblitz I found,但它并没有我想要的那样动态,因为组件的每个实例都被硬编码到不同的变量中,我也无法让它工作。

观察

不过我注意到的一件事是所有这三种方法都有两个共同点。首先在 app.component.html 中,他们使用 <ng-container #messageContainer></ng-container><ng-template #messageContainer></ng-template>。据我了解,这是将动态组件加载到 html 模板的地方。

app.component.ts 中的第二部分通常如下所示:

@ViewChild('messageContainer', { read: ViewContainerRef, static: true })
messageContainer: ViewContainerRef;

constructor (private cfr: ComponentFactoryResolver) { }

private createComponent (compClass) 
{
  const compFactory = this.cfr.resolveComponentFactory(compClass);
  return this.messageContainer.createComponent(compFactory);;
}

private loadNewComponentList () 
{
  this.messages.forEach((msg, idx) => 
  {
    this.destroyCompFromList(this.componentList[idx]);
    const comp = this.createComponent(componentMap[this._crtComp]);

    (comp.instance as any).message = msg;

    comp.changeDetectorRef.detectChanges();

    this.componentList[idx] = comp;
  });
}

这是摘自the first tutorial I tried.

现在我不太明白这段代码的作用,但从它的角度来看,ComponentFactoryResolver 似乎负责创建相同组件的多个实例。 ViewContainerRef 似乎是 html 模板中使用的内容。

这似乎是我应该前进的方向,但我不明白这些导入的 类 是做什么的,我什至不确定这种方法是否适合我的特定要求。

我希望有人能告诉我这个问题的简单解决方案,或者至少 adapt/simplify 满足我特定要求的教程。

谢谢。

你走在正确的轨道上。简要总结 the official guide from Angular 您应该创建一个指令来轻松获取 HTML 元素的 ViewContainerRef - 该组件将作为其兄弟注入。然后在需要时使用 ComponentFactoryResolver 创建您的组件。

个人会让指令负责创建组件,因为它允许您轻松地将它与 *ngFor 一起使用,并将所有动态内容与常规组件分开

@Directive({
    selector: '[appDynamicStatusBox]'
})
export class DynamicStatusBoxDirective implements OnInit, OnDestroy {
    @Input() config: MyData;

    componentRef: ComponentRef<StatusBoxComponent>;

    constructor(private resolver: ComponentFactoryResolver, public viewContainerRef: ViewContainerRef) {}

    ngOnInit(): void {
        const factory = this.resolver.resolveComponentFactory(StatusBoxComponent);
        this.viewContainerRef.clear();
        this.componentRef = this.viewContainerRef.createComponent(factory);
        this.componentRef.instance.someProperty= this.config.prop1;
        this.componentRef.instance.someOtherProperty= this.config.prop2;
    }

    ngOnDestroy(): void {
        this.componentRef.destroy();
    }
}
<ng-container *ngFor="let config of myConfigs; let i=index" appDynamicStatusBox [config]="config[i]"></ng-container>