Angular FormArray Example

By Arvind Rai, August 26, 2021
This page will walk through Angular FormArray example. Angular FormArray tracks the value and validity state of an array of FormControl, FormGroup or FormArray instances.
Let us create an array of FormControl using FormArray.
const fmArr = new FormArray([
	new FormControl(),
	new FormControl()
]); 
We can iterate this array in HTML template and can add, remove the form controls at run time.
Let us understand using FormArray in detail.

Technologies Used

Find the technologies being used in our example.
1. Angular 12.1.0
2. Node.js 12.14.1
3. NPM 7.20.3

FormArray

Find the constructor of FormArray class used to create its new instance.
constructor(controls: AbstractControl[], 
     validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[],
     asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]) 
1. controls : Array of child controls i.e. array of FormControl, FormGroup or FormArray instances.
2. validatorOrOpts : This is optional. This is the second argument in which we pass a synchronous validator or its array.
3. asyncValidator : This is optional. This is the third argument in which we pass an async validator or its array.

Find some of the methods of FormArray class.
at(): Returns the AbstractControl instance for the given index. The AbstractControl is the base class for FormControl, FormGroup and FormArray classes.
push(): Inserts the new AbstractControl at the end of array.
insert(): Inserts a new AbstractControl at the given index in the array.
removeAt(): Removes the control at the given index in the array.
setControl(): Sets a new control replacing the old one.
setValue(): Sets the value to every control of this FormArray.
patchValue(): Patches the value to available controls starting from index 0.
reset(): Resets the values.
getRawValue(): The aggregate value of the array.
clear(): Removes all controls in this FormArray.

With FormGroup

Find the code to create a FormGroup using FormArray.
studentForm = new FormGroup({
	name: new FormControl('', [ Validators.required ]),
	classmates: new FormArray([
		   new FormControl('Mahesh'),
		   new FormControl('Krishna')
	])
});
get name() {
	return this.studentForm.get('name') as FormControl;
}
get classmates() {
	return this.studentForm.get('classmates') as FormArray;
} 

FormArrayName

The FormArrayName syncs a nested FormArray to a DOM element. It is used under formGroup in HTML template. It accepts the string name of FormArray registered in the FormGroup created in the TypeScript. The selector of FormArrayName is formArrayName.
Find the HTML template code for the above form group.
<form [formGroup]="studentForm" (ngSubmit)="onFormSubmit()">
  <div>
	  Name: <input formControlName="name">
	  <label *ngIf="name.hasError('required')"> Enter Name. </label>
  </div>
  Classmates:
  <div formArrayName="classmates">
    <div *ngFor="let cm of classmates.controls; index as i">
      <input [formControlName]="i">
    </div>
  </div>  
  <button>SUBMIT</button>
</form> 

Using FormBuilder.array()

The FormBuilder.array() constructs a new FormArray. The FormBuilder has following methods.
group() : Construct a new FormGroup instance.
control() : Construct a new FormControl.
array() : Constructs a new FormArray.

Find the FormBuilder.array() method signature.
array(controlsConfig: any[], 
   validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], 
   asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]): FormArray 
controlsConfig: An array of child controls or control configs.
validatorOrOpts: This is optional. A synchronous validator function, or an array of such functions.
asyncValidator: This is optional. A single async validator or array of async validator functions.

Find the code snippet to create FormGroup using FormBuilder.group() method and FormArray using FormBuilder.array() method.
studentForm = this.formBuilder.group({
	name: new FormControl('', [ Validators.required ]),
	classmates: this.formBuilder.array([
		   new FormControl('Mahesh'),
		   new FormControl('Krishna')
	])
}); 

FormArray Validation

We know that FormArray accepts three arguments, first for controls, second for synchronous validators and third for async validators.
Here in our example, we are using only synchronous validators.
teamForm = this.formBuilder.group({
        ------
	employees: this.formBuilder.array([
		new FormControl()
	], [Validators.required, Validators.maxLength(5)])
}); 
In the above code, we are creating the FormArray using FormBuilder.array() method with required and maxLength validators.
Using required validator means, the FormArray must contain atleast one control i.e. array size must be minimum 1.
Using maxLength(5) validator means, the FormArray must not contain more than 5 controls i.e. array size cannot be more than 5.
The error messages can be displayed in HTML template as following.
<label *ngIf="employees?.errors?.required" class="error"> Employee required. </label>
<label *ngIf="employees?.errors?.maxlength" class="error">
  Max number of Employee can be 5 only. </label> 

Using FormArray Methods

Let us understand how to use FormArray methods. Find the code snippet of a form group.
teamForm = this.formBuilder.group({
        ------
	employees: this.formBuilder.array([
		new FormControl()
	])
});
get employees() {
        return this.teamForm.get('employees') as FormArray;
} 
Find the FormArray methods.
1. at(): Returns the control instance for the given index.
const emp = this.employees.at(2);
console.log(emp.value); 
In the above code, we are getting the control instance of index 2 of the array.
2. push(): Inserts the new control at the end of the array.
addEmployeeControl() {
	this.employees.push(new FormControl());
} 
3. removeAt(): Removes the control at the given index in the array.
deleteEmployeeControl(index: number) {
	this.employees.removeAt(index);
} 
4. insert(): Inserts a new control at the given index in the array.
insertEmployeeControl() {
	this.employees.insert(1, new FormControl());
} 
In the above code, a new control is added at index 1 and existing one at that index is pushed to the next index.
5. setControl(): Sets a new control replacing the old one.
setEmployeeControl() {
	this.employees.setControl(1, new FormControl('Krishna'));
} 
In the above code, a new control is set at index 1 replacing the existing one.
6. setValue(): Sets the value to every control of the array.
setEmployeeValue() {
	this.employees.setValue(['Mahesh', 'Vishal', 'Krishna']);
} 
The above code will work for FormArray of size 3. The value will be set to all the three controls. If the array size of FormArray is not 3, the setValue will throw error.
7. patchValue(): Patches the value to available controls starting from index 0.
patchEmployeeValue() {
	this.employees.patchValue(['Mahesh', 'Vishal', 'Krishna']);
} 
In the above code, the value will be set to first 3 controls. If the array size of FormArray is not 3, the patchValue will not throw error.
8. reset(): Resets the values of all controls of the array.
resetEmployees() {
	this.employees.reset();
} 
9. clear(): Removes all controls in the array.
clearEmployeeControls() {
	this.employees.clear();
} 
10. getRawValue(): The aggregate value of the array.
const rawVal = this.employees.getRawValue();
console.log(rawVal); 


Complete Example

team-management.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormArray, Validators, FormBuilder } from '@angular/forms';
import { TeamManagementService } from './team-management.service';

@Component({
	selector: 'app-team',
	templateUrl: './team-management.component.html'
})
export class TeamManagementComponent implements OnInit {
	constructor(
		private formBuilder: FormBuilder,
		private teamMngService: TeamManagementService) {
	}
	ngOnInit() {
	}
	teamForm = this.formBuilder.group({
		teamName: ['', Validators.required],
		employees: this.formBuilder.array([
			new FormControl()
		], [Validators.required, Validators.maxLength(5)])
	});
	get teamName() {
		return this.teamForm.get('teamName') as FormControl;
	}	
	get employees() {
		return this.teamForm.get('employees') as FormArray;
	}
	addEmployeeControl() {
		this.employees.push(new FormControl());
	}
	deleteEmployeeControl(index: number) {
		this.employees.removeAt(index);
	}
	insertEmployeeControl() {
		this.employees.insert(1, new FormControl());
	}
	setEmployeeControl() {
		this.employees.setControl(2, new FormControl('Shiv'));
	}
	setEmployeeValue() {
		this.clearEmployeeControls();
		this.addEmployeeControl();
		this.addEmployeeControl();
		this.addEmployeeControl();
		this.employees.setValue(['Mahesh', 'Vishal', 'Krishn']);
	}
	patchEmployeeValue() {
		this.employees.patchValue(['Mahesh', 'Vishal', 'Krishn']);
	}
	resetEmployees() {
		this.employees.reset();
	}
	clearEmployeeControls() {
		this.employees.clear();
	}
	onFormSubmit() {
		const emp = this.employees.at(0);
		console.log(emp.value);
		const rawVal = this.employees.getRawValue();
		console.log(rawVal);		
		this.teamMngService.saveTeam(this.teamForm.value);
		this.teamForm.reset();
	}
} 
team-management.component.html
<h3>Create New Team</h3>
<div class="team">
  <form [formGroup]="teamForm" (ngSubmit)="onFormSubmit()">
    <p><b>Team Name : </b> <input formControlName="teamName">
      <br /><label *ngIf="teamName?.dirty && teamName?.errors?.required" class="error">
        Team name required. </label>
    </p>
    <b> Employees in Team :</b><br><br>
    <label *ngIf="employees?.errors?.required" class="error"> Employee required. </label>
    <label *ngIf="employees?.errors?.maxlength" class="error">
      Max number of Employee can be 5 only. </label>
    <div formArrayName="employees">
      <div *ngFor="let emp of employees.controls; let i = index" class="employee">
        <p> <b>Employee {{i + 1}} : </b>
          <input [formControlName]="i">  
          <button type="button" (click)="deleteEmployeeControl(i)">Delete</button>
        </p>
      </div>
    </div>
    <button type="button" (click)="addEmployeeControl()">Add More Employee</button><br/>
    <button type="button" (click)="insertEmployeeControl()">Insert Employee at number 2</button><br/>
    <button type="button" (click)="patchEmployeeValue()">Patch Value</button><br/>
    <button type="button" (click)="setEmployeeValue()">Create Default Employee List</button><br/>    
    <button type="button" (click)="setEmployeeControl()">Set Default Employee at number 3</button><br/>
    <button type="button" (click)="resetEmployees()">Reset Employees</button><br/>
    <button type="button" (click)="clearEmployeeControls()">clear Employees</button><br/><br/>
    <button [disabled]="teamForm.invalid">SUBMIT</button>
  </form>
</div> 
team.ts
export interface Team {
	teamName: string;
	employees: string[];
} 
team-management.service.ts
import { Injectable } from '@angular/core';
import { Team } from './team';

@Injectable()
export class TeamManagementService {
	saveTeam(team: Team) {
		console.log('------------TEAM------------');
		console.log('Team Name: ' + team.teamName);
		console.log('----- Employee Detail -----');
		for (let emp of team.employees) {
			console.log('Emp Name: ' + emp);
			console.log('-------------------');
		}
	}
} 
app.component.ts
import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  template: `
           <app-team></app-team>
          `
})
export class AppComponent {
} 
styles.css
.team {
	border: 3px solid black;
	width: 400px;
}
.employee {
	border: 2px solid blue;
	width: 350px;
}
.error{
       color: red;
} 
.submitted{
       color: green;
       font-size: 20px;
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { TeamManagementComponent } from './team-management.component';
import { TeamManagementService } from './team-management.service';

@NgModule({
      imports: [
            BrowserModule,
            ReactiveFormsModule
      ],
      declarations: [
            AppComponent,
            TeamManagementComponent
      ],
      providers: [
            TeamManagementService
      ],
      bootstrap: [
            AppComponent
      ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
Find the print screen of the output.
Angular FormArray Example

References

FormArray
FormBuilder

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us