Angular 2/4:如何在动态创建的组件上添加表单控件? [英] Angular 2/4 : How to add form controls on dynamically created components?

查看:39
本文介绍了Angular 2/4:如何在动态创建的组件上添加表单控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ComponentFactoryResolver 创建一个响应式表单.

I'm trying to use the ComponentFactoryResolver to create a reactive form.

我想在该表单中添加的所有组件都是特定的,并实现 ControlValueAccessor 接口.

All the components I want to add in that form are specifics, and implement the ControlValueAccessor interface.

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

So, my question is simple : How can I add form controls on component created dynamically with ComponentFactoryResolver, without modifying my components ?

目前,我的代码如下:

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 访问它的输入.

This code works fine, my component is injected where I want, and I can access its Inputs using this.component.instance.

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

So, where should I add my formControlName directive ?

推荐答案

有同样的用例,我发现这个在 2020 年发布的解决方案可以完美解决您的问题:https://stackoverflow.com/a/63523127/2879716

Having the same use-case, I found this solution posted in 2020 to perfectly solve your issue: https://stackoverflow.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.

这篇关于Angular 2/4:如何在动态创建的组件上添加表单控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆