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>
问题
我正在尝试动态加载同一组件的多个实例,当用户提交表单时,新组件 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>