By Alligator and Bradley Kouchi

In Angular 2+, Reactive Forms are available to manage the state of a form. FormArray is used to track the value and validity state of form fields. You can use FormArray in Reactive Forms to add form fields dynamically from a response to a user event.
FormArray is used as an array that wraps around an arbitrary amount of FormControl, FormGroup, or even other FormArray instances. With FormArray you can add new form fields or a set of form fields declaratively.
In this article, we will go over an example application consisting of an order form for purchasing items. We will design this form to append a new form field for users to add items to their order.
To follow along with this article, you will need:
This post also assumes you are building from a fresh Angular project generated by @angular/cli. You can refer to this post if you’re getting started with Angular CLI.
FormArray and Initializing the FormFirst, ensure that you are importing ReactiveFormsModule in your application.
In app.module.ts, add an import for ReactiveFormsModule from the Angular forms module:
// ...
import { ReactiveFormsModule } from '@angular/forms';
Also, add ReactiveFormsModule to the module’s array of imports:
@NgModule({
...
imports: [
...
ReactiveFormsModule
]
...
})
In app.component.ts, add an import of FormBuilder, FormGroup, and FormArray from the Angular forms module:
// ...
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
Next, you will initialize the form using FormBuilder in the ngOnInit hook:
// ...
export class AppComponent {
orderForm: FormGroup;
items: FormArray;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.orderForm = this.formBuilder.group({
customerName: '',
email: '',
items: this.formBuilder.array([ this.createItem() ])
});
}
}
In this example, orderForm will consist of a customerName, email, and an array of items.
Notice that the items instance is a FormArray instead of a FormControl. We’re calling a createItem method to create a FormGroup as the first item in our array.
Next, we will add the createItem method to the AppComponent:
// ...
export class AppComponent {
// ...
createItem(): FormGroup {
return this.formBuilder.group({
name: '',
description: '',
price: ''
});
}
}
In our example, an item will consist of a name, description, and a price.
Now, we have an orderForm and items. We still have to implement a way to dynamically add new items.
FormArray DynamicallyWe can treat our FormArray like a regular array and push new items into it. Add the addItem method to the AppComponent:
// ...
export class AppComponent {
// ...
addItem(): void {
this.items = this.orderForm.get('items') as FormArray;
this.items.push(this.createItem());
}
}
Now we have addItem() defined. We still have to call addItem method in the template when the user clicks to add a new item.
Let’s use the formArrayName directive in the template to bind to the FormArray. In app.component.html, replace the content with our new template:
<form [formGroup]="orderForm">
<div
formArrayName="items"
*ngFor="let item of orderForm.get('items')['controls']; let i = index;"
>
...
</div>
...
</form>
Next, let’s add our FormGroup of FormControls for an item inside of the FormArray:
<form [formGroup]="orderForm">
<div
formArrayName="items"
*ngFor="let item of orderForm.get('items')['controls']; let i = index;"
>
<div [formGroupName]="i">
<input formControlName="name" placeholder="Item name">
<input formControlName="description" placeholder="Item description">
<input formControlName="price" placeholder="Item price">
</div>
</div>
...
</form>
Notice how the formGroupName directives now take an index instead of a name. We set it using the index that ngFor gives us.
After the FormArray, let’s add a button that when clicked calls addItem():
<form [formGroup]="orderForm">
<div
formArrayName="items"
*ngFor="let item of orderForm.get('items')['controls']; let i = index;"
>
<div [formGroupName]="i">
<input formControlName="name" placeholder="Item name">
<input formControlName="description" placeholder="Item description">
<input formControlName="price" placeholder="Item price">
</div>
</div>
<button type="button" (click)="addItem()">Add Item</button>
</form>
For debugging purposes, we can add some code to reveal FormControl’s value in the template by traversing our form:
<form [formGroup]="orderForm">
<div
formArrayName="items"
*ngFor="let item of orderForm.get('items')['controls']; let i = index;"
>
<div [formGroupName]="i">
<input formControlName="name" placeholder="Item name">
<input formControlName="description" placeholder="Item description">
<input formControlName="price" placeholder="Item price">
</div>
Exposed item name: {{ orderForm.controls.items.controls[i].controls.name.value }}
</div>
<button type="button" (click)="addItem()">Add Item</button>
</form>
At this point, we have a form that starts with a single item. Once we enter a name, description, and price for the first item, we can click the Add Item button and a new item is dynamically appended to the form.
You have completed an exploration of how Angular 2+ Reactive Forms and FormArray can be used to add new form fields dynamically. This pattern is useful for scenarios where a user may need to enter data more than once.
If you’d like to learn more about Angular, check out our Angular topic page for exercises and programming projects.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Alligator.io is a developer-focused resource that offers tutorials and insights on a wide range of modern front-end technologies, including Angular 2+, Vue.js, React, TypeScript, Ionic, and JavaScript.
Former Technical Editor at DigitalOcean. Expertise in areas including Vue.js, CSS, React, and more.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
I’m new to Angular. Does “last validated” date in your title mean you have updated this tutorial to use the latest version of Angular for 2021? Thanks.
Thanks! How would you save the inputs to a datasource? Please create a tutorial for that feature.
I did everything but got: Cannot find control with path: 'users -> userList -> 0 -> userRole'
Did anyone get something similar, if so how do I solve this?
How do I duplicate all the 1st form group fields values to all the other from groups? please help me…
Thank you…!
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.