更新时间:2023-11-24 10:45:28
有同样的用例,我发现这个在 2020 年发布的解决方案可以完美解决您的问题:https://***.com/a/63523127/2879716
Having the same use-case, I found this solution posted in 2020 to perfectly solve your issue: https://***.com/a/63523127/2879716
作者提供指向 StackBlitz 的链接,它展示了如何实现一个 FormControlOutletComponent
组件,该组件用作不同表单控件的单个入口点.例如,它在内部呈现了一个 CustomInputComponent
,它可以以您想要的任何方式实现.唯一的要求是它应该实现 ControlValueAccessor
接口.
The author provides a link to StackBlitz which shows how you can implement a FormControlOutletComponent
component which serves as a single entry point for different form controls. As an example, it renders a CustomInputComponent
inside, which can be implemented any way you want. The only requirement is that it should implement ControlValueAccessor
interface.
它增加了一层组件嵌套,因此动态组件创建实际上是在 FormControlOutletComponent
内部,而不是在您的主表单组件中.回答您问题的关键代码在这里:
It adds one more layer of components nesting, so dynamic component creation actually goes inside of FormControlOutletComponent
, not in your main form component.
The key code which answers your question is here:
// in FormControlOutletComponent's decalration
public ngOnInit(): void {
// 1. Get NgControl reference (defined by `NG_VALUE_ACCESSOR` provider)
const ngControl = this.injector.get(NgControl);
// 2. Resolve dynamic component factory and create a component instance
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(CustomInputComponent);
const componentRef = this.viewContainerRef.createComponent(componentFactory);
// 3. Important! Delegate all value-accessor-related work to the instance of the dynamic component
ngControl.valueAccessor = componentRef.instance;
}
因此,您的 FormControlOutletComponent
本身就变成了代理"用于其他动态表单组件.
As a result, your FormControlOutletComponent
becomes itself a "proxy" for other dynamic form components.
所以,要回答您最初的问题 - 我应该在哪里添加我的 formControlName 指令?",-您应该将它(或 ngModel
指令)添加到 <app-表单的 HTML 模板中的 form-control-outlet>
组件:
So, to answer your original question - "where should I add my formControlName directive?", - you should add it (or ngModel
directive) to the <app-form-control-outlet>
component in your form's HTML template:
<form [formGroup]="form">
<app-form-control-outlet [formControlName]="'controlName'"></app-form-control-outlet>
<!-- of course, you can render multiple components this way using ngFor -->
</form>
注意 FormControlOutletComponent
没有实现 ControlValueAccessor
接口,尽管它定义了 NG_VALUE_ACCESSOR
提供者:
Note that FormControlOutletComponent
doesn't implement ControlValueAccessor
interface, though it defines NG_VALUE_ACCESSOR
provider:
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormControlOutletComponent),
multi: true
}
]
它的作用就像魔法一样.我对这个解决方案的唯一不便是我不能简单地使用标准 HTML <input/>
作为动态组件 - 我必须围绕它创建自己的包装器,使用 ControlValueAccessor
接口,它只是将所有命令代理到 .如果有人知道如何简化这一点,那就太好了.
It works like a magic. The only inconvenience I'm having with this solution is that I can't simply use standard HTML <input/>
as a dynamic component - I have to create my own wrapper around it, with ControlValueAccessor
interface, which simply proxies all the commands to the <input/>
. If somebody knows how to simplify this, it would be great.