Angular FormArray setValue() and patchValue()

By Arvind Rai, July 22, 2019
Angular FormArray tracks the value and validity state of an array of FormControl, FormGroup or FormArray instances. setValue() and patchValue() are the methods of FormArray class.
setValue(): Sets the value of the FormArray. We need to pass an array that must match the structure of the control. If our array does not match the structure of the control, setValue() will throw error.
patchValue(): Patches the value of FormArray. We need to pass an array that should match the structure of the control. If the array that we pass, does not match the structure of the control completely, then patchValue() will patch only those fields which are matching with the structure of the control and rest will be as it is.

Here on this page we will discuss using setValue() and patchValue() with examples step-by-step.

Technologies Used

Find the technologies being used in our example.
1. Angular 8.0.3
2. TypeScript 3.4.3
3. Node.js 12.5.0
4. Angular CLI 8.0.6

FormArray setValue()

setValue() sets the value of the FormArray. We need to pass an array that matches the structure of the control. Create a sample FormArray.
myFormArray = new FormArray([
  new FormControl(),
  new FormControl(),
  new FormControl()	
]); 
In the above code we have created a FormArray with three FormControl. Now we will set the value and check output before and after setting value.
ngOnInit() {
  console.log(this.myFormArray.value);
  this.myFormArray.setValue(["AA", "BB", "CC"]);
  console.log(this.myFormArray.value);
} 
Find the output.
[null, null, null]

["AA", "BB", "CC"] 
We can see that before setting values we are getting null and after calling setValue(), we are getting our required values. We can observe that the array we pass to setValue() has length three that is matching the structure of the control as FormArray has three FormControl in our code.

If we pass the array which does not match the structure of control, then setValue() will throw error. Suppose we pass an array with lesser number of controls to setValue().
this.myFormArray.setValue(["AA", "BB"]); 
We will get an error.
ERROR Error: Must supply a value for form control at index: 2 
Hence to use setValue(), we need to pass array that must match the structure of the control completely.

FormArray patchValue()

patchValue() patches the value of FormArray. We need to pass an array to patchValue() that should match the structure of control either completely or partially. In patchValue() it is not necessary to pass an array that should exactly match the structure of control. patchValue() will try to patch value at its best and it will patch the given array to those part of structure of control which matches to given array. Find the sample FormArray with three FormControl.
myFormArray = new FormArray([
   new FormControl(),
   new FormControl(),
   new FormControl()	
]); 
Now we will patch value to myFormArray using patchValue().
ngOnInit() {
   console.log(this.myFormArray.value);

   this.myFormArray.patchValue(["AA", "BB"]);
   console.log(this.myFormArray.value);

   this.myFormArray.reset();
	
   this.myFormArray.patchValue(["AA"]);
   console.log(this.myFormArray.value);
} 
Find the output.
[null, null, null]
["AA", "BB", null]
["AA", null, null] 
We can see that we are passing array with length lesser than three to myFormArray whereas myFormArray has three controls. When we pass array with length two, it sets value to two controls and when we pass array with length one, it sets value to one control.

FormArray setValue() and patchValue() Example using FormBuilder

We will create a reactive form using FormBuilder. In our form we will create one text box and a FormArray control. Find the code snippet.
teamForm = this.formBuilder.group({
   teamName: ['', Validators.required],
   employees: this.formBuilder.array([
	this.formBuilder.group(new Employee()),
	this.formBuilder.group(new Employee())
   ])
}); 
Our FormArray control with name employees, consists the array of FormGroup which has form control name as the fields of Employee class. Find this class.
export class Employee {
	empId = '';
	empName = ''; 
	skill = '';
} 
So in our reactive form, FormArray consists the array of FormGroup which has form controls named as empId, empName and skill.
Find the getter method for our FormArray.
get employees(): FormArray {
   return this.teamForm.get('employees') as FormArray;
} 
Now we will use setValue() and patchValue() for employees which is the instance of FormArray.

1. setValue(): In our FormArray, we have empId, empName and skill controls. Find the code snippet.
setEmployeeValues() {
	this.employees.setValue([
		{ empId: "111", empName: "Mohan", skill: "Java"},
		{ empId: "112", empName: "Krishna", skill: "Angular"}	
	]);
} 
In our UI, we will call setEmployeeValues() by a button. As we have two rows of employee data to set, so FormArray must also have the same structure of control. After setting values UI will be as following.
Angular FormArray setValue() and patchValue()
In above UI, if we add more employee or delete any employee and try to set value, then structure will not match to our data to set and hence we will get error in console.
We can also set values using the object of Employee class. We need to pass array of Employee to setValue() method.
setEmployeeValues() {
	let emp1 = new Employee();
	emp1.empId = "111";
	emp1.empName = "Mohan";
	emp1.skill = "Java";

	let emp2 = new Employee();
	emp2.empId = "112";
	emp2.empName = "Krishna";
	emp2.skill = "Angular";		

	this.employees.setValue([emp1, emp2]);
} 

2. patchValue(): patchValue() does not need every field to configure. We may pass same number of fields or lesser number of fields. In our FormArray, we have empId, empName and skill controls. Find the code snippet.
patchEmployeeValues() {
	this.employees.patchValue([
		{ empId: "111", empName: "Mohan"},
		{ empId: "112", skill: "Angular"}
	]);
} 
We will call patchEmployeeValues() by a button on UI. In first row we have omitted skill field and in second row we have omitted empName field. After patching values our UI will be as following.
Angular FormArray setValue() and patchValue()

Complete Example

employee.ts
export class Employee {
	empId = '';
	empName = ''; 
	skill = '';
} 
team.ts
import { Employee } from './employee';

export class Team {
	teamName: string;
	employees: Employee[];
} 
team-management.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormArray, Validators, FormBuilder } from '@angular/forms';
import { Observable } from 'rxjs';

import { TeamManagementService } from './team-management.service';
import { Team } from './team';
import { Employee } from './employee';

@Component({
	selector: 'app-team',
	templateUrl: './team-management.component.html'
})
export class TeamManagementComponent implements OnInit {
	teamForm: FormGroup;
	isValidFormSubmitted = null;
	allSkills: Observable<any[]>;
	constructor(
		private formBuilder: FormBuilder,
		private teamMngService: TeamManagementService) {
	}
	ngOnInit() {
		this.allSkills = this.teamMngService.getSkills();

		this.teamForm = this.formBuilder.group({
			teamName: ['', Validators.required],
			employees: this.formBuilder.array([
				this.formBuilder.group(new Employee()),
				this.formBuilder.group(new Employee())
			])
		});	

	}
	get teamName() {
		return this.teamForm.get('teamName');
	}	
	get employees(): FormArray {
		return this.teamForm.get('employees') as FormArray;
	}
	addEmployee() {
		let fg = this.formBuilder.group(new Employee());
		this.employees.push(fg);
	}
	deleteEmployee(idx: number) {
		this.employees.removeAt(idx);
	}
	onFormSubmit() {
		this.isValidFormSubmitted = false;
		if (this.teamForm.invalid) {
			return;
		}
		this.isValidFormSubmitted = true;		
		let team: Team = this.teamForm.value;
		this.teamMngService.saveTeam(team);
		this.teamForm.reset();
	}
	patchEmployeeValues() {
		this.employees.patchValue([
			{ empId: "111", empName: "Mohan"},
			{ empId: "112", skill: "Angular"}
		]);
	}
	setEmployeeValues() {
		this.employees.setValue([
			{ empId: "111", empName: "Mohan", skill: "Java"},
			{ empId: "112", empName: "Krishna", skill: "Angular"}	
		]);

        /**
		let emp1 = new Employee();
		emp1.empId = "111";
		emp1.empName = "Mohan";
		emp1.skill = "Java";

		let emp2 = new Employee();
		emp2.empId = "112";
		emp2.empName = "Krishna";
		emp2.skill = "Angular";		

		this.employees.setValue([emp1, emp2]); */		
	}
	resetTeamForm() {
		this.teamForm.reset();
	}
} 
team-management.component.html
<h3>Create New Team</h3>
<div *ngIf="isValidFormSubmitted" class="submitted"> Form submitted successfully. </div>
<div class="team">
  <form [formGroup]="teamForm" (ngSubmit)="onFormSubmit()">
    <p>Team Name :
      <input formControlName="teamName">
      <br/>
      <label *ngIf="teamName.invalid && isValidFormSubmitted != null && !isValidFormSubmitted" class="error">
        Team name is required.
      </label>
    </p>
    <div class="all-emp">
      <b>Employees in Team:</b>
      <br>
      <br>
      <div formArrayName="employees">
        <div *ngFor="let emp of employees.controls; let i = index" [formGroupName]="i" class="employee">
          <p>
            <b>Employee : {{i + 1}}</b>
          </p>
          <p>Emp Id :
            <input formControlName="empId">
          </p>
          <p>Emp Name :
            <input formControlName="empName">
          </p>
          <p>Skill :
            <select formControlName="skill">
              <option *ngFor="let skill of allSkills | async" [ngValue]="skill.name">
                {{ skill.displayName }}
              </option>
            </select>
          </p>
          <p>
            <button type="button" (click)="deleteEmployee(idx)">Delete</button>
          </p>
        </div>
      </div>
      <button type="button" (click)="addEmployee()">Add More Employee</button>
    </div>
    <br/>
    <button>SUBMIT</button>
    <button type="button" (click)="setEmployeeValues()">SET VALUE</button>
    <button type="button" (click)="patchEmployeeValues()">PATCH VALUE</button>
    <button type="button" (click)="resetTeamForm()">RESET</button>
  </form>
</div> 
team-management.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Team } from './team';

const ALL_SKILLS = [
	{name: 'Java', displayName: 'Java'},
	{name: 'Angular', displayName: 'Angular'},
	{name: 'Dot Net', displayName: 'Dot Net'}
 ];

@Injectable({
	providedIn: 'root'
})
export class TeamManagementService {
	getSkills() {
		return of(ALL_SKILLS);
	}
	saveTeam(team: Team) {
		console.log('------------TEAM------------');
		console.log('Team Name: ' + team.teamName);
		console.log('----- Employee Details -----');
		for (let emp of team.employees) {
			console.log('Emp Id: ' + emp.empId);
			console.log('Emp Name: ' + emp.empName);
			console.log('Emp Skill: ' + emp.skill);
			console.log('-------------------');
		}
	}
} 
app.component.ts
import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  template: `
           <app-team></app-team>
          `
})
export class AppComponent {
} 
styles.css
.employee {
    border: 2px solid blue;
    width: 275px;
}
.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';

@NgModule({
      imports: [
            BrowserModule,
            ReactiveFormsModule
      ],
      declarations: [
            AppComponent,
            TeamManagementComponent
      ],
      providers: [],
      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

References

Angular FormArray
Angular FormBuilder

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us