106
votes

FormGroup:

A FormGroup aggregates the values of each child FormControl into one object, with each control name as the key.

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

FormArray:

A FormArray aggregates the values of each child FormControl into an array.

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

When should one be used over the other?

4

4 Answers

139
votes

FormArray is a variant of FormGroup. The key difference is that its data gets serialized as an array (as opposed to being serialized as an object in case of FormGroup). This might be especially useful when you don’t know how many controls will be present within the group, like dynamic forms.

Let me try to explain by a quick example. Say, you have a form where you capture a customer's order for Pizza. And you place a button to let them add and remove any special requests. Here is the component's html part:

<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>

and here is the component class defining and handling special requests:

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 offers more flexibility than FormGroup in the sense that it is easier to manipulate FormControls using "push", "insert" and "removeAt" than using FormGroup's "addControl", "removeControl", "setValue" etc. FormArray methods ensure the controls are properly tracked in the form's hierarchy.

hope this helps.

35
votes

In order to create a reactive forms, a parent FormGroup is a must. This FormGroup can further contain formControls, child formGroups or formArray

FormArray can further contain array of formControls or a formGroup itself.

When should we use formArray?

Please read this beautiful post which explains the usage of formArray

The interesting example in that blog is about the trips formGroup

The structure of trips formGroup using formControl and formArray would look something like:

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),
               })
               )
      }))
})

Do not forget to play with this DEMO, and notice the usage of array for cities and places of a trip.

8
votes

From: Anton Moiseev Book “Angular Development with Typescript, Second Edition.” :

When you need to programmatically add (or remove) controls to a form, use FormArray. It’s similar to FormGroup but has a length variable. Whereas FormGroup represents an entire form or a fixed subset of a form’s fields, FormArray usually represents a collection of form controls that can grow or shrink.

For example, you could use FormArray to allow users to enter an arbitrary number of emails.

0
votes

From angular documentation you can see that

FormArray is an alternative to FormGroup for managing any number of unnamed controls. As with form group instances, you can dynamically insert and remove controls from form array instances, and the form array instance value and validation status is calculated from its child controls. However, you don't need to define a key for each control by name, so this is a great option if you don't know the number of child values in advance.

Let me show you their example and try to explain how I understand this. You can see source here

Imagine a form witch has following fields

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

Here we have firstName, lastName, address and aliases All field together are form group so we wrap everything in group. At the same time address is like a subgroup so we wrap it in another group (You can look at template for better understanding)! Every form control here hes key except aliases and it means that you can push in it values as much as you want like simple array using formBuilder methods like push.

This is how I understand it, hope it helps someone.