In this post, you are going to learn everything that you need to know about the Angular FormArray construct, available in Angular Reactive Forms.

We are going to learn exactly what is an Angular FormArray, what is the difference towards a normal FormGroup, when to use it and why.

We are going to give an example of a common use case that would be hard to implement without a FormArray: an in-place editable table with multiple form controls per line, where new editable rows can be added or removed on demand by the user.

Table Of Contents

In this post, we will cover the following topics:

  • What is an Angular FormArray?
  • What is the difference between a FormArray and a FormGroup?
  • The FormArray API
  • Creating an in-place editable table using FormArray
  • The formArrayName directive
  • When to use an Angular FormArray vs a FormGroup?
  • Summary

This post is part of our ongoing series on Angular Forms, you can find all the articles available here.

So without further ado, let's get started learning everything that we need to know about Angular FormArray!

What is an Angular FormArray?

In Angular Reactive Forms, every form has a form model defined programmatically using the FormControl and FormGroup APIs, or alternatively using the more concise FormBuilder API, which we will be using throughout this guide.

In most cases, all the form fields of a form are well known upfront, and so we can define a static model for a form using a FormGroup:

As we can see, using a FormGroup, we can define a group of related form controls, their initial values, and form validation rules, and give property names for each field of the form.

This is possible because this is a static form with a pre-defined number of fields that are all known upfront, which is the most common case when it comes to forms.

But what about other more advanced but still frequently encountered situations where the form is much more dynamic, and where not all form fields are known upfront (if any)?

Imagine a dynamic form where form controls are added or removed to the form by the user, depending on its interaction with the UI.

An example would be a form that is fully dynamically built according to data coming from the backend!

Another more common example of a dynamic form would be an in-place editable table, where the user can add or remove lines containing multiple editable form controls:

Angular Form Array Example - an in-place editable table

In this dynamic form, the user can add or remove new controls to the form by using the Add and Delete buttons.

Each time that the user clicks on the Add button, a new lesson row will be added to the form containing two new form controls.

We will be implementing this example in this guide using FormArray. But the main question is: why can't this form be implemented using FormGroup?

What is the difference between a FormArray and a FormGroup?

Unlike our initial example where we defined the form model using FormGroup via a call to the fb.group() API, in the case of an in-place editable table, we don't know the number of form controls upfront.

And this is because we can't know upfront the number of rows that the table will have. The user might add an unknown number of rows using the add button, and he might even remove them midway through by using the delete lesson button.

We wouldn't be able to define a form model using FormGroup, without knowing the exact number of rows. Also, it would be hard to give to the fields pre-defined names.

But we can define a form model for this in-place editable table using a
FormArray instead.

A FormArray, just like a FormGroup, is also a form control container, that aggregates the values and validity state of its child components.

But unlike a FormGroup, a FormArray container does not require us to know all the controls up front, as well as their names.

Actually, a FormArray can have an undetermined number of form controls, starting at zero! The controls can then be dynamically added and removed depending on how the user interacts with the UI.

Each control will then have a numeric position in the form controls array, instead of a unique name.

Form controls can be added or removed from the form model anytime at runtime using the FormArray API.

The FormArray API

These are the most commonly used methods available in the FormArray API:

  • controls: This is an array containing all the controls that are part of the array
  • length: This is the total length of the array
  • at(index): Returns the form control at a given array position
  • push(control): Adds a new control to the end of the array
  • removeAt(index): Removes a control at a given position of the array
  • getRawValue(): Gets the values of all form controls, via the control.value property of each control

Let's now learn how we can use this API to implement an in-place editable data table.

Creating an in-place editable table using FormArray

Let's first define a reactive form model, using the FormBuilder API:

As we can see, we did not add any other controls to our form, except for the editable data table itself.

This is just to keep the example simple, but nothing would prevent us from adding any other form properties if we needed to.

In our case, all the controls inside the editable table are going to be inside the FormArray instance, built using the fb.array() API.

Initially, the FormArray instance is empty and contains no form controls, meaning that the editable table is initially empty.

We have added to the component a getter for the lessons property, in order to make it simple to access the FormArray instance in a simple and type-safe way.

Also, notice in the editable table screenshot shown earlier, that each row in the table contains two controls: a lesson title field and a lesson level (or difficulty) field.

We would like these fields to be part of the parent form of this component, and affect its validity state. If an error occurs in the title of one of the lessons, then the whole form should be considered invalid.

For this, we are going to create one FormGroup for each table row, and we are going to add to it two form fields, with their own form control validators.

Dynamically adding controls to a FormArray

In order to add new rows to the table, we are going to need an Add Lesson button in our component template:

When this button gets clicked, we are going to trigger the following code:

As we can see, in order to add a row to the table, we are first creating the form model of a simple form with only the two fields of each row: the lesson title and difficulty.

We then take this lesson row FormGroup, which is itself also a form control and we add it to the last position of the FormArray by using the push API.

Remember, we can add any form control to the FormArray, and this includes also form groups, which are also controls themselves.

Dynamically removing controls from a FormArray

If you notice in the editable table screenshot shown earlier, every lesson row has a delete icon associated with it, that the user can use to delete the whole lesson row.

Here is what the click handler looks like for this button:

In order to delete a lesson row, all we have to do is to use the removeAt API to remove the corresponding FormGroup from the FormArray, at a given row index.

Notice that in both the add lesson and remove lesson buttons, all we have to do to add or remove a row is to add or remove controls from the form model.

And this is because our UI model is built by looping through the FormArray elements, and by adding form controls accordingly.

The formArrayName directive

To conclude our exercise, we will now show the full code of the editable table component, and review the template. Let's start with the component code:

And here is what the editable table component template looks like:

Let's now break down what is going on here:

  • This editable table is implemented using commonly used Angular Material components
  • We are applying the formGroup directive to a form container, and linking it to the parent form of the component
  • This means that the parent form will contain all the child controls of the form, including every control of every row created by the user
  • Inside the parent form, we apply the formArrayName directive, which links a container element to the lessons property of the form
  • This directive is what allows for the FormArray instance to track the values and validity state of its child components
  • We are then using ngFor to loop through the form controls of the lessons FormArray
  • every control of the FormArray is a form group itself, containing two row controls (title and level)
  • We then use the formGroup directive to define a nested form for every table row, containing two lesson row controls
  • We then use the formControlName directive to bind the lesson fields to the template, like we usually do in any reactive form

As we can see, our editable table form is simply a form with a list of nested child forms, one form per table row. And each table row form contains two controls inside it.

And with this, our in-place editable table is fully implemented! The user can freely add and remove lesson rows to the form.

The parent form will only be considered valid once every row added by the user is filled in with valid values.

Summary

Let's quickly summarize everything that we have learned about FormArray, and do one final comparison to FormGroup.

As we can see, the FormArray construct is very powerful and comes in especially handy in situations where we want to build our form model in a more dynamic way.

When to use an Angular FormArray vs a FormGroup?

When building the model of an Angular form, most of the time we want to use a FormGroup and not a FormArray, so that should be the default choice.

As we can see, the FormArray container is ideal for those rarer situations when we don't know the number of form controls upfront or their names.

The FormArray container is ideal for more dynamic situations where the content of the form is in general being defined at runtime, depending on user interaction or even backend data.

In our example, we have used FormArray to implement an in-place editable table, because we believe that is its most common use case.

In the table example, the controls in the FormArray were FormGroup instances, containing form controls themselves, but notice that this is not mandatory.

A FormArray can contain any type of controls inside it, and this includes plain form controls, FormGroup instances and even other FormArray instances.

With FormArray, you can implement in Angular all sorts of advanced dynamic form scenarios, but keep in mind that unless you really need the power of
FormArray, FormGroup will be the correct choice for most cases.

I hope that you have enjoyed this post, if you would like to learn a lot more about Angular Forms, we recommend checking the Angular Forms In Depth course, where all sorts of advanced forms topics (including FormArray) are covered in much more detail.

Also, if you have some questions or comments please let me know in the comments below and I will get back to you.

To get notified of upcoming posts on Angular, I invite you to subscribe to our newsletter:

And if you are just getting started learning Angular, have a look at the Angular for Beginners Course: