何时使用 FormGroup 与 FormArray?

Posted

技术标签:

【中文标题】何时使用 FormGroup 与 FormArray?【英文标题】:When to use FormGroup vs. FormArray? 【发布时间】:2017-05-08 10:05:41 【问题描述】:

FormGroup:

FormGroup 将每个子 FormControl 的值聚合为一个 对象,以每个控件名称为键。

const form = new FormGroup(
  first: new FormControl('Nancy', Validators.minLength(2)),
  last: new FormControl('Drew')
);

FormArray:

FormArray 将每个子 FormControl 的值聚合到一个 数组。

const arr = new FormArray([
  new FormControl('Nancy', Validators.minLength(2)),
  new FormControl('Drew')
]);

什么时候应该使用一个而不是另一个?

【问题讨论】:

【参考方案1】:

FormArray 是 FormGroup 的变体。主要区别在于它的数据被序列化为一个数组(而不是在 FormGroup 的情况下被序列化为一个对象)。当您不知道组中将存在多少控件时,这可能特别有用,例如动态表单。

让我试着用一个简单的例子来解释一下。假设您有一个表格,您可以在其中捕获客户的披萨订单。然后您放置一个按钮,让他们添加和删除任何特殊请求。这是组件的 html 部分:

<section>
  <p>Any special requests?</p>
  <ul formArrayName="specialRequests">
    <li *ngFor="let item of orderForm.controls.specialRequests.controls; let i = index">
      <input type="text" formControlName="i">
      <button type="button" title="Remove Request" (click)="onRemoveSpecialRequest(i)">Remove</button>
    </li>
  </ul>
  <button type="button" (click)="onAddSpecialRequest()">
    Add a Request
  </button>
</section>

这里是定义和处理特殊请求的组件类:

constructor () 
  this.orderForm = new FormGroup(
    firstName: new FormControl('Nancy', Validators.minLength(2)),
    lastName: new FormControl('Drew'),
    specialRequests: new FormArray([
      new FormControl(null)
    ])
  );


onSubmitForm () 
  console.log(this.orderForm.value);


onAddSpecialRequest () 
  this.orderForm.controls
  .specialRequests.push(new FormControl(null));


onRemoveSpecialRequest (index) 
  this.orderForm.controls['specialRequests'].removeAt(index);

FormArray 提供了比 FormGroup 更大的灵活性,因为使用“push”、“insert”和“removeAt”比使用 FormGroup 的“addControl”、“removeControl”、“setValue”等更容易操作 FormControl。FormArray 方法确保控件在表单的层次结构中得到正确跟踪。

希望这会有所帮助。

【讨论】:

如果您尝试编辑表单怎么办?如何迭代和添加控件? 你会如何将它重构为组件? 是否可以将带有 key:value 的对象添加到表单数组中,而不仅仅是值? 如何设置表单标签名称?初始化表单控件时是否有任何选项可以设置?由于表单是动态的,我们无法设置它的值。【参考方案2】:

为了创建响应式表单,必须有一个父级FormGroup。这个FormGroup 还可以包含formControls、子formGroupsformArray

FormArray 可以进一步包含formControls 的数组或formGroup 本身。

什么时候应该使用formArray?

请阅读这篇漂亮的post,它解释了formArray的用法

那个博客中有趣的例子是关于旅行的formGroup

使用formControlformArray 的行程formGroup 的结构类似于:

this.tripForm = this.fb.group(
    name: [name, Validators.required],
     cities: new FormArray(
       [0] ---> new FormGroup(
           name: new FormControl('', Validators.required),
               places: new FormArray(
                  [0]--> new FormGroup(
                      name: new FormControl('', Validators.required),
                         ),
                      [1]--> new FormGroup(
                         name: new FormControl('', Validators.required),
                      )
                  )
              ), 
       [1] ---> new FormGroup(
           name: new FormControl('', Validators.required),
           places: new FormArray(
               [0]--> new FormGroup(
                   name: new FormControl('', Validators.required),
               ),
               [1]--> new FormGroup(
                   name: new FormControl('', Validators.required),
               )
               )
      ))
)

别忘了玩这个DEMO,注意数组在citiesplaces 中的用法。

【讨论】:

@scopchanov 可能对文字没有太多解释,但表单结构表示确实提供了一些思路。让我知道我们是否可以添加任何内容来改进答案:) 好吧,如果有人说“解释”,那么我希望能看到。恕我直言,根据 SO 定义,您的答案非常接近于“仅链接答案”,因为就在它到达重点的地方,即 我们何时应该使用 formArray?,一个指向提供了一篇博文,但未引用其中的任何重要部分。您确实发布了一些代码,但再次没有任何解释。如果您引用了这篇博文中的两条规则,那将会产生巨大的影响。 @scopchanov 当然,当我有时间补充时,我会改进这个答案。【参考方案3】:

来自:Anton Moiseev 的书“Angular Development with Typescript, Second Edition”。 :

当您需要以编程方式添加(或删除) 控件表单时,请使用FormArray。它类似于 FormGroup,但有一个长度变量FormGroup 表示整个表单或表单字段的固定子集FormArray 通常表示可以增长的表单控件集合或缩小

例如,您可以使用 FormArray 来允许用户输入任意数量的电子邮件。

【讨论】:

【参考方案4】:

从 Angular 文档中你可以看到

FormArray 是 FormGroup 的替代方案,用于管理任意数量的 未命名的控件。与表单组实例一样,您可以动态地 从表单数组实例中插入和删除控件,以及表单 数组实例值和验证状态是从它的 子控件。但是,您不需要为每个 按名称控制,所以如果您不知道 预先设置子值的数量。

让我向您展示他们的示例,并尝试解释我是如何理解这一点的。可以看源码here

想象一个表单女巫有以下字段

  profileForm = this.fb.group(
    firstName: ['', Validators.required],
    lastName: [''],
    address: this.fb.group(
      street: [''],
      city: [''],
      state: [''],
      zip: ['']
    ),
    aliases: this.fb.array([
      this.fb.control('')
    ])
  );

这里我们有firstNamelastNameaddressaliases 所有字段一起是表单组,所以我们将所有内容包装在group 中。同时address 就像一个子组,所以我们把它包装在另一个group 中(你可以看模板更好地理解)!这里的每个表单控件都是key,除了aliases,这意味着您可以使用formBuilder 之类的push 等方法像简单数组一样将其值推入任意数量。

这就是我的理解,希望对某人有所帮助。

【讨论】:

以上是关于何时使用 FormGroup 与 FormArray?的主要内容,如果未能解决你的问题,请参考以下文章

formControlName 必须与父 formGroup 指令一起使用

ERROR 错误:formArrayName 必须与父 formGroup 指令一起使用

formGroupName必须与父formGroup指令一起使用

formGroupName 必须与父 formGroup 指令一起使用

初始化formGroup与根据下拉框

typescript Angular Service将FormGroup与LocalStorage同步(获取和设置)