Forms

Angular FormArray - Complete Guide

Learn how to build dynamic Angular Forms with FormArray by adding or removing form controls at runtime. Build an in-place editable data table.

Angular FormArray - Complete Guide — Forms article by Angular University on Angular In Depth
Angular FormArray - Complete Guide — Forms article by Angular University on Angular In Depth
On this page · 5 sections

The Angular FormArray construct, part of the Reactive Forms module, is the focus of this guide. We'll explore its definition, how it differs from a standard FormGroup, and the scenarios where its use is warranted.

To illustrate a practical application, we'll build an in-place editable table where each row contains multiple form controls. This example will demonstrate how to dynamically add or remove rows, a task that becomes difficult without FormArray.

Table Of Contents

This guide covers the following topics:

  • Defining the Angular FormArray
  • Comparing FormArray and FormGroup
  • Exploring the FormArray API
  • Building an in-place editable table with FormArray
  • Understanding the formArrayName directive
  • Choosing between FormArray and FormGroup
  • Recap and final thoughts

This article is part of a larger series on Angular Forms. You can find related content here.

Let’s begin our exploration of the Angular FormArray.

In Angular Reactive Forms, the form model is defined programmatically using APIs like FormControl and FormGroup, or the more concise FormBuilder, which we'll use here.

Typically, form fields are known in advance, allowing a static model definition with a FormGroup:

Using a FormGroup, you establish a group of related controls, their initial values, validation rules, and property names.

This approach works because the form's structure is fixed, and all fields are known upfront.

However, situations arise where the form is dynamic, and the fields are not predetermined.

Consider a form where controls are added or removed by user interaction, or one built entirely based on backend data.

A common dynamic form example is an in-place editable table, where the user can add or remove rows, each containing multiple editable controls:

Angular Form Array Example - an in-place editable table

In this scenario, users can add or remove controls via the Add and Delete buttons. Each click on Add inserts a new row with two fresh controls into the form.

We'll implement this using FormArray. But why is a FormGroup not suitable here?

Unlike static forms where the model is defined with fb.group(), an editable table's row count is unknown at the start.

The number of rows can change arbitrarily as the user interacts with the UI, making it impossible to predefine a FormGroup model with fixed fields and names.

Instead, we can model this dynamic structure with a
FormArray.

Like a FormGroup, a FormArray is a container that aggregates the values and validity of its children.

However, a FormArray doesn't require knowing its controls or their names in advance. It can start with zero controls and grow or shrink dynamically based on user actions.

Each control within the array is referenced by its numeric index, rather than a unique name.

The FormArray API allows adding or removing controls at any point during runtime.

Here are the most frequently used methods from the FormArray API:

  • controls: An array containing all the child controls
  • length: The total number of controls in the array
  • at(index): Gets the control at the specified position
  • push(control): Appends a new control to the end of the array
  • removeAt(index): Deletes the control at the given position
  • getRawValue(): Retrieves the value of each control via its value property

Now, let's see how to use this API to build an in-place editable table.

First, we define the reactive form model using FormBuilder:

For simplicity, the form model only contains the editable table. Additional form properties could be added if needed.

All controls for the table reside within a FormArray instance, created with the fb.array() API.

Initially, this FormArray is empty, representing an empty table.

We add a getter for the lessons property to easily and safely access the FormArray instance.

Notice that each table row has two controls: a lesson title and a difficulty level.

These fields must be part of the parent form, affecting its validity. An error in any lesson's title, for example, should invalidate the entire form.

To achieve this, we'll create a FormGroup for each row, containing two form controls with their validation rules.

Dynamically adding controls to a FormArray

To add table rows, we include an "Add Lesson" button in the template:

Clicking this button triggers the following code:

To add a row, we construct a FormGroup representing a simple form with the two row fields: title and difficulty.

This FormGroup is a control itself, so we append it to the FormArray using the push method.

The FormArray can hold any type of control, including nested FormGroup instances.

Dynamically removing controls from a FormArray

Each row has a delete icon, as seen in the earlier screenshot, allowing the user to remove the entire row.

Here's the click handler for the delete button:

To remove a row, we use the removeAt API, specifying the index of the corresponding FormGroup within the FormArray.

Both add and remove operations modify the form model directly. Because the UI iterates over the FormArray, these changes reflect automatically in the template.

Let's examine the full component and template code. First, the component logic:

And the corresponding template:

Here’s a breakdown of the template structure:

  • The table uses common Angular Material components.
  • The formGroup directive links the form element to the parent form, encompassing all child controls.
  • Within this, the formArrayName directive connects the container to the lessons form property.
  • This directive enables the FormArray to track child values and validity.
  • An ngFor loop iterates over the controls in the lessons FormArray.
  • Each control is a FormGroup containing two row controls: title and level.
  • The formGroup directive defines a nested form for each row.
  • The formControlName directive binds the specific fields of the row controls to the template.

In essence, our editable table is a form containing a list of nested child forms, one per row. Each nested form has its two controls.

This completes the implementation. Users can freely add and remove lesson rows.

The parent form is only valid when all user-added rows contain valid data.

Summary

Let's summarize what we've learned about FormArray and compare it to FormGroup.

The FormArray is a robust tool for dynamically building form models.

When to use an Angular FormArray vs a FormGroup?

Typically, a FormGroup is the default choice for defining form models, as most forms have a known structure.

A FormArray is suited for less common cases where the form's controls and their names are not known in advance.

It excels in dynamic scenarios where the form content is finalized at runtime, influenced by user interaction or external data.

Here, we used FormArray for an in-place editable table, which is a common use case.

In our example, the FormArray contained FormGroup instances, but this isn't required. A FormArray can hold any type of control, including simple controls or even other FormArray instances.

With FormArray, a wide range of advanced dynamic form scenarios is possible in Angular. However, stick with FormGroup for most situations unless you specifically need the flexibility of
FormArray.

For a deeper dive into Angular Forms, including more advanced topics like FormArray, the Angular Forms In Depth course is a comprehensive resource.

Questions or comments? Please share them below and we'll respond.

To stay updated on new Angular posts, subscribe to our newsletter.

New to Angular? Start with the Angular for Beginners Course:

Angular FormArray - Complete Guide — figure 2
AU
Angular University

Writes about RxJS, Components, Signals. Active 2015–2026.

All 79 articles →