可重用子组件中的 Angular react 形式 : Problem with FormArrays: `formGroupName` must be used with a parent formGroup directive

标签 angular parent-child angular-reactive-forms formarray formgroups

我正在尝试通过示例 (full example on stackblitz) 来描述问题

如果我尝试以带有子组件的简单“formControls”或“formGroups”的形式放置 react 形式的某些部分,则没有问题。 (参见上面关于 stackblitz 的示例)。 FormGroupDirective按预期工作。

但是如果我尝试将 FormArray 放置在子组件中,我会遇到麻烦,因为:

<div [formGroupName]="i">
  <!--
    Error: formGroupName must be used 
    with a parent formGroup directive.
  -->
<div>

Reactive-Form 是一种简单的形式:

  ngOnInit () {
    this.newForm = this.fb.group({
      id: [{value: '4711', disabled: this.idReadOnly}, Validators.required],
      chapter: this.fb.group({
        name: ['Some Chapter', Validators.required]
      }),
      faq: this.fb.array(this.faqArray)
    });
  }

如上所述,id 没有问题和 chapter ,它们在自定义子组件中实现,例如:

<fe-input 
  [controlPath]="['id']"
  placeholder="Child-FormControl ID"
></fe-input>

<my-form-group 
[controlPath]="['chapter', 'name']"
placeholder="Child-FormGroup Chapter"
[required]="true"
>
</my-form-group>

在 stackblitz 上的应用程序中,您将看到工作部分“ID”和“章节”。

formArray 相同的方法:

<my-form-array 
[controlPath]="['faq']" 
placeholder="Child-FormArray FAQ"
[required]="true"
></my-form-array>

应该按我的想法工作,但部分 <div [formGroupName]="i">仅在子组件内导致上面已经提到的错误:

Error: formGroupName must be used 
with a parent formGroup directive.

如果我在原始文件中使用它(定义 react 形式的地方),它可以正常工作。

我很困惑,也许我只是忽略了一个简单的问题?有人能帮我吗?整个示例可在此处在线获取:( >> stackblitz )

更新 1:

我已经将@yurzui 的解决方案与


viewProviders: [{ 
  provide: ControlContainer, 
  useExisting: FormGroupDirective 
}]

并且错误“Error: formGroupName must be used..”消失了。之后,我为formArray字段集成了自定义组件,它们无法获取控件值。我想我已经接近解决方案了。那是自定义组件:

import { Component, OnInit, Input } from '@angular/core';
import {
  FormControl,
  FormGroupDirective
} from '@angular/forms';

@Component({
  selector: 'fe-input',
  template: `
    <mat-form-field>
      <input
        matInput
        [placeholder]="placeholder"
        [formControl]="control"
        [required]="required"
      />
      <mat-error>
        This is a required field!
      </mat-error>
    </mat-form-field>
  `,
  styles: [

  ]
})
export class FormElementInputComponent implements OnInit {
  // Values to be set:
  @Input() controlPath: any;
  @Input() placeholder: string;
  @Input() controlValue: any;
  @Input() required = false;

  // That's the reuseable control
  control: FormControl;

  constructor(private fgd: FormGroupDirective) {}

  ngOnInit() {
    this.control = this.fgd.control.get(
      this.controlPath
    ) as FormControl;
  }
}

最后是 my-form-array 的模板部分:

 template: `
  <div fxLayout="column">
    <div *ngFor="let c of control.controls; index as i">

      <div [formGroupName]="i">

        <fe-input 
        [controlPath]="q"
        placeholder="Question"
        [required]="required"
      ></fe-input>

      <fe-input 
        [controlPath]="a"
        placeholder="Answer"
        [required]="required"
      ></fe-input>
      <div>

    </div>
  </div>
  `,

最佳答案

首先,您的 FormArray 是 FormControls 的 FormArray,它们获取对象的值,而不是 FormGroup 的 FormArray。创建表单时必须更改

this.newForm = this.fb.group({
  id: [{value: '4711', disabled: this.idReadOnly}, Validators.required],
  chapter: this.fb.group({
    name: ['Some Chapter', Validators.required]
  }),
  faq: this.fb.array(this.faqArray.map(x=>this.fb.group({
    q:x.q,
    a:x.a
  })))
}); 

其次,您可以使用“其他方式”来处理 FormGroup 的 FormArray,它不使用 [formGroupName="i"] else [formGroup]="control"。是的

<!--remove this that not work
<div *ngFor="let c of control.controls; index as i">
      <div [formGroupName]="i">
           ....
      <div>
</div>
-->
<!--use [formGroup] -->
<div  *ngFor="let c of control.controls; index as i">
    <div [formGroup]="c">
          ....
    </div>
</div>

好吧,在 formGroup 中你需要你的 fe-input [controlPath]="'q'"和 [controlPath]="'a'"

我删除了表单组,因为它也是错误的,尝试使用 [formGroup] 并使用 viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]

你看到你的 forked stackblitz

更新 如果我们使用标记 formArray

<my-form-array 
[controlPath]="['faq','a','q']"
placeholder="Child-FormArray FAQ"
[required]="true"
></my-form-array>

我们可以在 ngOnInit 中改变我们的 my-form-array

this.control = this.fgd.control.get(
      this.controlPath[0]
    ) as FormArray;

和 .html

   <div *ngFor="let c of control.controls; index as i">
      <div [formGroup]="c">
       <fe-input *ngFor="let fields of controlPath.slice(1)"
        [controlPath]="fields"
        placeholder="Question"
        [required]="required"
      ></fe-input>
    </div>

the re-forked stackblitz

关于可重用子组件中的 Angular react 形式 : Problem with FormArrays: `formGroupName` must be used with a parent formGroup directive,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56842459/

相关文章:

angular - 如何使用分页导出 Angular Material 表(mat-table)?

javascript - 第 3 方添加到日历下拉列表未显示在子页面中

angular - ngrx 组件存储效果在 promise 错误后不会触发

javascript - 父子树适用于嵌套的 'if-else' 但不适用于 javascript 中的 'function recursion'

angular - 如何查看除特定控件外的所有 FormControls ValueChanges?

angular - 如何在 angular2 应用程序中使用 cron-parser 模块

flutter - Bloc 流未正确更新

jquery:如何在表中使用 ">"和children()

angular - 为什么在将 Formarray 添加到嵌套表单时会得到一个数组

angular - 在 formBuilder.group 响应式(Reactive)表单中添加动态属性