具有相同的用例,我发现 2020 年发布的这个解决方案可以完美解决您的问题:https://stackoverflow.com/a/63523127/2879716 https://stackoverflow.com/a/63523127/2879716
作者提供StackBlitz 的链接 https://stackblitz.com/edit/dynamically-rendering-angular-ng-value-accessor?file=src/app/app.component.ts其中展示了如何实现FormControlOutletComponent
组件,用作不同表单控件的单个入口点。作为一个例子,它渲染了一个CustomInputComponent
在里面,可以以任何你想要的方式实现。唯一的要求是它应该实施ControlValueAccessor
界面。
它增加了一层组件嵌套,因此动态组件创建实际上是在FormControlOutletComponent
,不在您的主表单组件中。
回答您问题的关键代码在这里:
// 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
本身成为其他动态表单组件的“代理”。
因此,要回答您最初的问题 - “我应该在哪里添加我的 formControlName 指令?”, - 您应该添加它(或ngModel
指令)到<app-form-control-outlet>
表单 HTML 模板中的组件:
<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
提供者:
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormControlOutletComponent),
multi: true
}
]
它的作用就像魔术一样。我对这个解决方案的唯一不便是我不能简单地使用标准 HTML<input/>
作为一个动态组件 - 我必须围绕它创建我自己的包装器,ControlValueAccessor
接口,它只是将所有命令代理到<input/>
。如果有人知道如何简化它,那就太好了。