Angular 2/4:如何在动态创建的组件上添加表单控件?

2024-04-05

我正在尝试使用 ComponentFactoryResolver 创建反应式表单。

我想要以该形式添加的所有组件都是特定的,并实现 ControlValueAccessor 接口。

所以,我的问题很简单:如何在使用 ComponentFactoryResolver 动态创建的组件上添加表单控件,而不修改我的组件?

目前,我的代码如下:

component: ComponentRef<any>;
form: FormGroup;

@ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;

constructor(private resolver: ComponentFactoryResolver, private fb: FormBuilder) {}

ngOnInit(): void {
  this.form = this.fb.group({});
  const component: any = MyStringComponent;
  const factory: any = this.resolver.resolveComponentFactory<any>(component);
  this.component = this.container.createComponent(factory);
}

和模板:

<form
  [formGroup]="form">
  <ng-container #container>

  </ng-container>

</form>

这段代码工作正常,我的组件被注入到我想要的地方,并且我可以使用 this.component.instance 访问它的输入。

那么,我应该在哪里添加 formControlName 指令?


具有相同的用例,我发现 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/>。如果有人知道如何简化它,那就太好了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular 2/4:如何在动态创建的组件上添加表单控件? 的相关文章

随机推荐