Working with Angular FormArray
Tags: angular, javascript
Published: 2021-08-24 14:47:05

---
title: Working with Angular FormArray
published: true
description: In this post, we’ll teach you how to use the Angular FormArray to add dynamic data into the Angular form and validate it. 
tags: angular, javascript 
canonical_url: https://blog.jscrambler.com/working-with-angular-formarray/
//cover_image: https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-vworking-with-angular-formarray.jpg
---
Forms are an integral part of the web application development scheme, and there are many different ways we can use a form. For instance, you can have multiple forms on a page or you can have just a single form. Depending on the use case the form will have, it might even be required for the forms to be created dynamically. In this post, we’ll explore exactly this topic and go over the Angular FormArray in reactive forms.

## What is an Angular FormArray?
In our previous blog post, you created [Angular reactive forms](https://blog.jscrambler.com/building-user-registration-form-with-reactive-forms-in-angular-7/?utm_source=dev.to&utm_medium=referral&utm_campaign=angular-form-array) using `FormControl` and `FormGroups` APIs. However, sometimes you might have the need to repeat a form multiple times dynamically based on how the user interacts with the user interface. Angular `FormArray` is a container that allows you to do that since it can be used to collect dynamically created controls.

## Why do we need it?
`FormArray` provides a way to collect the dynamically created forms in one place. You can access each of the forms using the index and the controls inside it. Managing and validating the dynamically created forms’ data becomes easier, similar to the reactive forms.

## Using Angular FormArray
Enough of the talking, now let's see how to use a FormArray in an Angular project.
### Setting up the project
Assuming that you already have the Angular CLI installed, use it to create a new Angular project.
```
ng new form-array
```
Select the default options when prompted for whether to use routing and the stylesheets option. 

Once you have the project created, navigate to the project directory and start the project.
```
cd form-array
npm start
```
You will have the project running at `localhost:4200`.
### Adding Bootstrap
To style up the project let's add the bootstrap library using npm.
```
npm install bootstrap jquery popper.js
```
Once you have it installed, add the following dependencies to the `angular.json` file. Go to `architect -> build -> options` and add the following `styles` and `scripts`:
```
"styles": [
    "src/styles.css",
    "node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
    "node_modules/jquery/dist/jquery.min.js",
    "node_modules/popper.js/dist/umd/popper.min.js",
    "node_modules/bootstrap/dist/js/bootstrap.min.js"
]
```
Now you should be able to use bootstrap. Let's add some HTML design to our app.

Add the following HTML to the `app.component.html` file:
```
<div class="container">
  <main class="main">
    <div class="row">
      <div class="col-md-12 col-lg-12">
        <h4 class="mb-3">Customer Information</h4>
        <form class="needs-validation" novalidate>
          <div class="row g-3">
            <div class="col-sm-6">
              <label for="firstName" class="form-label">First name</label>
              <input type="text" class="form-control" id="firstName" placeholder="First name" value="" required>
            </div>

            <div class="col-sm-6">
              <label for="lastName" class="form-label">Last name</label>
              <input type="text" class="form-control" id="lastName" placeholder="Last name" value="" required>
            </div>

            <div class="col-6">
              <label for="username" class="form-label">Username</label>
              <div class="input-group">
                <input type="text" class="form-control" id="username" placeholder="Username" required>
              </div>
            </div>

            <div class="col-sm-6">
              <label for="email" class="form-label">Email Address</label>
              <input type="email" class="form-control" id="email" placeholder="Email address" value="" required>
            </div>

          </div>


          <div class="card mt-2r">
            <div class="card-header ">
              <div class="header-container">
                <span class="product-header">
                  Add Product Information
                </span>
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
                  class="bi bi-plus-square-fill" viewBox="0 0 16 16">
                  <path
                    d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z" />
                </svg>
              </div>


            </div>
            <div class="card-body">
              <div class="row">
                <div class="col-12">

                  <ul class="list-group">
                    <li class="list-group-item">
                      <div class="row">
                        <div class="col-4">
                          <input type="text" class="form-control" id="firstName" placeholder="Product name" value=""
                            required>
                        </div>
                        <div class="col-6">
                          <input type="text" class="form-control" id="firstName" placeholder="Product description"
                            value="" required>
                        </div>
                        <div class="col-2">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                            class="bi bi-trash-fill" viewBox="0 0 16 16">
                            <path
                              d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                          </svg>
                        </div>
                      </div>
                    </li>
                    <li class="list-group-item">
                      <div class="row">
                        <div class="col-4">
                          <input type="text" class="form-control" id="firstName" placeholder="Product name" value=""
                            required>
                        </div>
                        <div class="col-6">
                          <input type="text" class="form-control" id="firstName" placeholder="Product description"
                            value="" required>
                        </div>
                        <div class="col-2">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                            class="bi bi-trash-fill" viewBox="0 0 16 16">
                            <path
                              d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                          </svg>
                        </div>
                      </div>
                    </li>
                    <li class="list-group-item">
                      <div class="row">
                        <div class="col-4">
                          <input type="text" class="form-control" id="firstName" placeholder="Product name" value=""
                            required>
                        </div>
                        <div class="col-6">
                          <input type="text" class="form-control" id="firstName" placeholder="Product description"
                            value="" required>
                        </div>
                        <div class="col-2">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                            class="bi bi-trash-fill" viewBox="0 0 16 16">
                            <path
                              d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                          </svg>
                        </div>
                      </div>
                    </li>
                    <li class="list-group-item">
                      <div class="row">
                        <div class="col-4">
                          <input type="text" class="form-control" id="firstName" placeholder="Product name" value=""
                            required>
                        </div>
                        <div class="col-6">
                          <input type="text" class="form-control" id="firstName" placeholder="Product description"
                            value="" required>
                        </div>
                        <div class="col-2">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                            class="bi bi-trash-fill" viewBox="0 0 16 16">
                            <path
                              d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                          </svg>
                        </div>
                      </div>
                    </li>
                    <li class="list-group-item">
                      <div class="row">
                        <div class="col-4">
                          <input type="text" class="form-control" id="firstName" placeholder="Product name" value=""
                            required>
                        </div>
                        <div class="col-6">
                          <input type="text" class="form-control" id="firstName" placeholder="Product description"
                            value="" required>
                        </div>
                        <div class="col-2">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                            class="bi bi-trash-fill" viewBox="0 0 16 16">
                            <path
                              d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                          </svg>
                        </div>
                      </div>
                    </li>
                  </ul>
                </div>
              </div>
            </div>
          </div>
          <button class="mt-20 w-100 btn btn-primary btn-lg" type="submit">Create Customer</button>
        </form>
      </div>
    </div>
  </main>

  <footer class="my-5 pt-5 text-muted text-center text-small">
    <p class="mb-1">&copy; 2017–2021 Company Name</p>
    <ul class="list-inline">
      <li class="list-inline-item"><a href="#">Privacy</a></li>
      <li class="list-inline-item"><a href="#">Terms</a></li>
      <li class="list-inline-item"><a href="#">Support</a></li>
    </ul>
  </footer>
</div>
```
Add the following CSS to the `app.component.css` file.
```
  .container {
    max-width: 960px;
  }

  .main{
      margin-top: 2rem;
  }

  .mt-20{
      margin-top: 20px;
  }

  .mt-2r{
      margin-top: 2rem;
  }

  .product-header{
      font-weight: 500;
  }
  .header-container{
    display: flex;
    flex-direction: row;
    justify-content: space-between;
  }
```
Save the changes and you will be able to view the following in your Angular app.

<center><img src="https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-working-with-angular-formarray.png" alt="jscrambler-blog-working-with-angular-formarray-first-screen"></center>

As you can see in the above screenshot, the product information block has multiple products added. That is where you'll be using the `FormArray` to create and manage multiple products.

### Create Angular Reactive Forms
Let's start by importing `ReactiveFormsModule` in the `app.module.ts` file.
```
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```
Now go to your `app.component.ts` file and create a reactive form to manage the customer information.

Start by importing `FormBuilder` in the `AppComponent`.
```typescript
import { FormBuilder } from  '@angular/forms';
``` 
Next, create an instance of `FormBuilder` in the constructor method.
```javascript
constructor(private  formBuilder : FormBuilder){}
```
Implement a `OnInit` in the `AppComponent` and define a variable for the reactive form group. Here is how the `app.component.ts` file looks :
```typescript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  
  customerInfo : FormGroup;

  constructor(private formBuilder : FormBuilder){}

  ngOnInit(){
    
  }
}
```
Let's initialize the `customerInfo` reactive form group.
```typescript
  ngOnInit(){
    this.customerInfo = this.formBuilder.group({
      firstName : [],
      lastName : [],
      username : [],
      email : [],
      products : this.formBuilder.array([])
    })
  }
```
As seen in the above code, `products` is defined as a `FormArray`. Now let's bind the reactive form to the HTML in the `app.component.html` file.

Start by adding the `formGroup` directive to the `form` in the `app.component.html` file.
```html
<form  [formGroup]="customerInfo"  class="needs-validation">
.......
.......
</form>
```
Next add the `formControlName` attribute to the respective `input` controls.
```html
<div class="row g-3">
    <div class="col-sm-6">
        <label for="firstName" class="form-label">First name</label>
        <input type="text" formControlName="firstName" class="form-control" id="firstName" placeholder="First name" value="" required>
    </div>

    <div class="col-sm-6">
        <label for="lastName" class="form-label">Last name</label>
        <input type="text" formControlName="lastName" class="form-control" id="lastName" placeholder="Last name" value="" required>
    </div>

    <div class="col-6">
        <label for="username" class="form-label">Username</label>
        <div class="input-group">
            <input type="text" class="form-control" id="username" placeholder="Username" required>
        </div>
    </div>

    <div class="col-sm-6">
        <label for="email" class="form-label">Email Address</label>
        <input type="email" class="form-control" id="email" placeholder="Email address" value="" required>
    </div>

</div>
```
You need to iterate over the `products` form Array to bind to the HTML. You'll be using `ngFor` to iterate over the `products` form array controls. Here is how the `ul` element from the HTML code looks:
```html
<ul class="list-group">
    <li class="list-group-item" formArrayName="products" *ngFor="let product of customerInfo.get('products')['controls']; let i = index;">
        <div [formGroupName]="i" class="row">
            <div class="col-4">
                <input type="text" formControlName="name" class="form-control" id="firstName" placeholder="Product name" value="" required>
            </div>
            <div class="col-6">
                <input type="text" formControlName="description" class="form-control" id="firstName" placeholder="Product description" value="" required>
            </div>
            <div class="col-2">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
                    <path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                </svg>
            </div>
        </div>
    </li>
</ul>
```
As seen in the above code, you have assigned a couple of directives.

 - **formArrayName="products"** to denote the formArrayName from the reactive  form `customerInfo`
 - **[formGroupName]="i"** to assign a form group to each set of product, which you have assigned as index.

Save the above changes and run the app. You'll be able to view the following screen.

<center><img src="https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-working-with-angular-formarray-1.png" alt="jscrambler-blog-working-with-angular-formarray-initial-form"></center>

### Adding Items to Angular FormArray
Now let's see how to insert or add some data to the products form array. Add a click event to the plus icon HTML and define the same in the `app.component.ts`.

```html
<svg (click)="addProduct()" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-plus-square-fill" viewBox="0 0 16 16">
    <path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z" />
</svg>
```

Get a reference to the `products` formArray from `customerInfo`. Once you have the reference, you can push a formGroup each time a new entry is required in the `products` array. Here is how the `addProduct` method looks:
```typescript
  addProduct(){
    let products = this.customerInfo.get('products') as FormArray;
    products.push(this.formBuilder.group({
      name : [],
      description : []
    }));
  }
```
Save the above changes and refresh the app. From the app click on the plus icon to add a new product. You'll be able to add a new entry to the products list.

### Saving Angular FormArray Data

Add a click event to the create customer button.
```html
<button  (click)="createCustomerInfo()"  class="mt-20 w-100 btn btn-primary btn-lg"  type="button">Create Customer</button>
```
Define the event in the `app.component.ts` file. You can access the complete value of the `customerInfo` as a JSON object.
```typescript
  createCustomerInfo(){
    console.log('data is ', this.customerInfo.value);
  }
```
Save the changes and fill the form. Add some data to the products list also. Click on the create customer info button and you will be able to see the data in the browser console.

<center><img src="https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-working-with-angular-formarray-2.png" alt="jscrambler-blog-working-with-angular-formarray-log-data"></center>

### Prepopulate Angular FormArray From Existing Data

You saw how to create a form array and how to get the user entered data on the click of a button. You also will be required to populate the form array from some existing data. Let's have a look at how to achieve it.

Let's define a method called `setDefaultData`. Let's call the method once the form has been initialized inside `ngOnInit`.

```typescript
  ngOnInit(){
    this.customerInfo = this.formBuilder.group({
      firstName : [],
      lastName : [],
      username : [],
      email : [],
      products : this.formBuilder.array([])
    })
    this.setDefaultData();
  }
```

From inside the `setDefaultData` method, you'll make a call to the `addProduct`. 
```typescript
  setDefaultData(){
    this.addProduct("tyre", "rubber material");
  }
```
Earlier you didn't pass anything for `name` and `description`. Let's modify the `addProduct` to pass parameters.
```typescript
  addProduct(name = "", desc = ""){
    let products = this.customerInfo.get('products') as FormArray;
    products.push(this.formBuilder.group({
      name : [name],
      description : [desc]
    }));
  }
```
Save the above changes and refresh the application. On load you'll be able to see a default product entry in products.

<center><img src="https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-working-with-angular-formarray-3.png" alt="jscrambler-blog-working-with-angular-formarray-default"></center>

## Validating Angular FormArray
Let's have a look at how to validate the form array controls and show error messages.

First you need to add the required validators while creating a new product form group inside the `addProduct` method.
```typescript
  addProduct(name = "", desc = ""){
    let products = this.customerInfo.get('products') as FormArray;
    products.push(this.formBuilder.group({
      name : [name, [Validators.required]],
      description : [desc, [Validators.required]]
    }));
  }
```
Now let's add a span element adjacent to the input control.
```html
<span class="validation">* required</span>
```
Add the following CSS to the `app.component.css` file.
```css
.validation{
  color: red;
}
```
Using the formGroup `product` check for errors and show the error span. Add the following `ngIf` directive to show the message conditionally when the field is empty.
```html
<span  *ngIf="product.get('name').errors && product.get('name').hasError('required')"  class="validation">* required</span>
```
Here is the modified portion of the `app.component.html`.
```html
<ul class="list-group">
    <li class="list-group-item" formArrayName="products" *ngFor="let product of customerInfo.get('products')['controls']; let i = index;">
        <div [formGroupName]="i" class="row">
            <div class="col-4">
                <input type="text" formControlName="name" class="form-control" id="firstName" placeholder="Product name" value="" required>
                <span *ngIf="product.get('name').errors && product.get('name').hasError('required')" class="validation">* required</span>
            </div>
            <div class="col-6">
                <input type="text" formControlName="description" class="form-control" id="firstName" placeholder="Product description" value="" required>
                <span *ngIf="product.get('description').errors && product.get('description').hasError('required')" class="validation">* required</span>

            </div>
            <div class="col-2">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
                    <path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" />
                </svg>
            </div>
        </div>
    </li>
</ul>
```
Save the above changes and load the app. Click the plus button to add a new entry and you will be able to see the validation message.

<center><img src="https://blog.jscrambler.com/content/images/2021/07/jscrambler-blog-working-with-angular-formarray-4.png" alt="jscrambler-blog-working-with-angular-formarray-validation"></center>

## Wrapping It Up

In this tutorial, you learned how to use FormArray to add dynamic data to the Angular form. You also learned how to access that dynamic data and validate the  Angular FormArray.

Lastly, if you want to learn how you can protect your Angular application, be sure to check [our guide](https://blog.jscrambler.com/how-to-protect-angular-code-against-theft-and-reverse-engineering/?utm_source=dev.to&utm_medium=referral&utm_campaign=angular-form-array).

For detailed information on `FormArray`, do check out [the official documentation](https://angular.io/api/forms/FormArray).

Source code from this tutorial is available at [GitHub](https://github.com/jay3dec/form-array-demo).