Angular 16 FormArray Dynamic Nested Form Tutorial

Last Updated on by in Angular
Sometimes a user needs the additional form fields to insert the dynamic data. Angular 16 FormArray API allows creating nested form fields.In this tutorial, we will learn about how to build the nested forms using Angular FormArray API with Reactive Forms.

Angular FormArray is a class in Angular that represents an array of FormControl, FormGroup, or FormArray instances.

It provides a way to manage and validate multiple form controls dynamically.

To create dynamic nested form in Angular we will use FormArray. You have to import it from the @angular/forms module.

If you are new to Reactive Forms, please refer to Full Angular Reactive Forms & Form Validation Tutorial.

Set up Angular Project

Install the Angular CLI with below command.

npm install @angular/cli -g

Now, you have to install the brand new Angular project using below command.

ng new angular-demo

Angular CLI asks for your choices while setting up the project…

Would you like to add Angular routing?
Select y and Hit Enter.

Which stylesheet format would you like to use? (Use arrow keys)
Choose SCSS and hit Enter

Use command to navigate into the project directory:

cd angular-demo

Remove Angular TypeScript Errors

To get rid from the errors:

Property ‘xxxName’ comes from an index signature, so it must be accessed with [‘xxxName’]

This setting makes sure profound consistency between accessing a field via the “dot” (obj.key) syntax, and “indexed” (obj["key"]) and the way which the property is declared in the type.

Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:

Make sure to set following properties to false in tsconfig.json file:

"compilerOptions": {
 ...
 ...
   "strict": false,
   "noPropertyAccessFromIndexSignature": false,
 ...
 ...
},
  "angularCompilerOptions": {
    "strictTemplates": false
  }

Understand Nested Forms in Angular

Let’s assume if a user requires to add an item using the form. In this kind of condition, you have to create a form which allows a user to add dynamic form fields to add additional data.

Setting Up Reactive Form

Importing ReactiveFormsModule API

To work with Reactive Forms in Angular, please import ReactiveFormsModule service in app.module.ts file.

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule
  ],
})

export class AppModule { }

Understand Basic Reactive Forms Services

Reactive forms are used to manage complex data entered by the user in the form. Let’s focus on some of the useful services of Reactive Forms.

AbstractControl: This is the main class for controlling the behavior and properties of, FormGroup, FormControl, and FormArray.

FormBuilder: It provides helpful methods to create control instances in Angular 7 Reactive Forms.

FormGroup: FormGroup is a top-level API which maintains the values, properties and validation state of a group of AbstractControl instance in Angular.

FormControl: It communicates with an HTML Form element like input or select tag, this api handles the individual form value and validation state.

FormArray: FormArray API maintains the values, properties and validation state of an array of the AbstractControl instances.

ngSubmit: This event is called when the form is submitted.

Setting Up Reactive Form in Angular Component HTML Template

app.component.html

<!-- Form starts -->
<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
   <button type="submit" class="btn btn-danger btn-lg btn-block">Submit Form</button>
</form><!-- Form ends -->

Setting Up Reactive Form

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormArray } from "@angular/forms";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
  constructor(public fb: FormBuilder) {}

  /*############ Registration Form ############*/
  registrationForm = this.fb.group({
    addDynamicElement: this.fb.array([])
  })

  // Submit Registration Form
  onSubmit() {
    alert(JSON.stringify(this.registrationForm.value))
  }

}

Setting Up Nested Form Layout Using HTML & FormArrayName Directive

Let’s set up the HTML layout for creating Nested forms group in Angular. I will be using following directives to work with nested forms in Angular.

formArrayName: It syncs a nested FormArray to a DOM element.

*ngFor: It’s a structural directive provided by Angular that loops over every item in a collection.

<div class="jumbotron text-center">
  <h2 class="display-5">
    Angular 16 Nested Form Example
  </h2>
</div>

<div class="container">
  <div class="row custom-wrapper">
    <div class="col-md-12">

      <!-- Form starts -->
      <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">

        <!-- Add items dynamically-->
        <div class="group-gap" formArrayName="addDynamicElement">
          <h5 class="mb-3">Add Products</h5>
          <div class="mb-3">
            <button type="button" class="btn btn-sm btn-success mb-3 btn-block" (click)="addItems()">Add Items</button>
            <ul class="subjectList">
              <li *ngFor="let item of addDynamicElement.controls; let i = index">
                <input type="text" class="form-control" [formControlName]="i">
              </li>
            </ul>
          </div>

          <!-- Submit Button -->
          <button type="submit" class="btn btn-danger btn-lg btn-block">Submit Form</button>
        </div>

      </form><!-- Form ends -->

    </div>
  </div>
</div>

Understand Dynamic Forms Array

I will add a JavaScript getter method to access the addDynamicElement form control. Then i will assign FormArray to form control, it will make it an array.

Once we are done with this process, then i will addItems() function and push the dynamically created form control into the addDynamicElement array.

/*############### Add Dynamic Elements ###############*/
get addDynamicElement() {
  return this.registrationForm.get('addDynamicElement') as FormArray
}

addItems() {
  this.addDynamicElement.push(this.fb.control(''))
}

Let’s checkout the output.

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormArray, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})

export class AppComponent {
  constructor(public fb: FormBuilder) {}

  /*################ Registration Form ################*/
  registrationForm = this.fb.group({
    addDynamicElement: this.fb.array([]),
  });

  /*############### Add Dynamic Elements ###############*/
  get addDynamicElement() {
    return this.registrationForm.get('addDynamicElement') as FormArray;
  }

  addItems() {
    this.addDynamicElement.push(this.fb.control(''));
  }

  // Submit Registration Form
  onSubmit() {
    alert(JSON.stringify(this.registrationForm.value));
  }
}

Angular Nested Form Demo

We’ve created nested form with Angular, we have used reactive forms to manage nested data required by the user.

The following command will start a development server, compile and run your app.

ng serve --open

Let’s check out below how does it work?

Angular 16 FormArray Dynamic Nested Form Tutorial

Conclusion

A dynamic nested form is a very useful form component. A dynamic web form is a type of form that allows users to dynamically add or remove nested form fields on the go.

It comes to handy when you require to collect repeating data from the users without having the knowledge the exact number of entries beforehand.