Angular FormBuilder Example

By Arvind Rai, August 20, 2021
This page will walk through Angular FormBuilder example. The FormBuilder is used to create a big reactive form with minimum code in Angular application. The FormBuilder methods are group(), control() and array() that returns FormGroup, FormControl and FormArray respectively. Using FormBuilder we can directly pass object or array of object of a class to create the form. We need to create form HTML template with formArrayName by assigning the field name of that class.
Suppose we want to create a FormGroup with some fields, then first create a class with those fields and then pass the instance of that class to FormBuilder.group() and it will return FormGroup with form controls named as class fields. After form submit, we can get complete form value as an object of a class. In this way, with the help of FormBuilder, we can create form using object of a class, set values in the form using object of a class and also we can fetch form values as an object of a class after form submit. Now we will provide complete FormBuilder example step-by-step.

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

Project Structure

Find the project structure of our demo application.
angular-demo
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--employee.ts
|   |   |--department.ts
|   |   |--team.ts
|   |   |--team-data.ts
|   |   |--team-management.service.ts
|   |   |--team-management.component.ts
|   |   |--team-management.component.html
|   |   |--app.component.ts
|   |   |--app.module.ts
|   |   
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json

FormBuilder

FormBuilder creates reactive form with minimum code using FormGroup, FormControl and FormArray. FormBuilder has following methods.
group(): Creates FormGroup.
control(): Creates FormControl.
array(): Creates FormArray.

Find the sample example to create a form with FormBuilder.
this.teamForm = this.formBuilder.group({
   teamName: ['', Validators.required ],
   teamManager: '',
   teamDept: this.formBuilder.group(new Department()),
   employees: this.formBuilder.array([]) 
});

Using FormBuilder.group()

FormBuilder.group() constructs a new FormGroup with the given configuration. We can pass the parameter as following.
1.
teamDept: this.formBuilder.group({
   deptHead: '',
   deptName: ''
})
2. We can also pass the object of the class. Suppose we have a Department class with fields deptHead and deptName. Using FormBuilder.group() we can create FormGroup as following.
teamDept: this.formBuilder.group(new Department()) 


The HTML template for both the above example, will be same.
<div formGroupName="teamDept" class="department"> 
  <p>Department Head : <input formControlName="deptHead"></p>
  <p>Department Name : <input formControlName="deptName"></p>
</div> 
If we want to pass default values to the fields of the form, we can assign values as follows.
teamDept: this.formBuilder.group({
   deptHead: 'Modi',
   deptName: 'M Commerce'
}) 
When we use object to pass to the FormBuilder.group() method then we need to set default values in the object.

Using FormBuilder.array()

FormBuilder.array() constructs new FormArray for the given configuration. We can pass configuration as an array of FormGroup or FormControl. We can get FormArray using FormBuilder.array() in following ways.
1.
employees: this.formBuilder.array([{'empId': '', 'empName': '', 'skill': ''}]) 
2. We can pass empty array and can add FormArray at run time.
Create a method to get the FormArray instance.
get empFormArray(): FormArray{
    return this.teamForm.get('employees') as FormArray;
}
To add any element in FormArray at run time, FormArray has FormArray.push() method. Now suppose we want to add FormGroup in the FormArray instance, we can write code as follows.
addEmployee(){
    let fg = this.formBuilder.group(new Employee());
    this.empFormArray.push(fg);	  
}
3. We can use FormGroup.setControl() to replace existing instance of FormGroup, FormControl or FormArray by new one. Suppose we want to replace FormArray instance at run time, first we will create an array of FormArray using FormBuilder.array() and replace existing data with new instance using FormGroup.setControl(). Find the code snippet.
let employeeFormGroups = team.employees.map(employee => this.formBuilder.group(employee));
let employeeFormArray = this.formBuilder.array(employeeFormGroups);
this.teamForm.setControl('employees', employeeFormArray); 
For all the above three cases, HTML template can be created as follows.
<div formArrayName="employees"> 
   <div *ngFor = "let emp of empFormArray.controls; let idx = index" [formGroupName]="idx" class="employee">
     <p> <b>Employee : {{idx + 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> 	
   </div>
</div> 
If we want to remove an element from FormArray for a given index, we can use removeAt() method of FormArray as following.
deleteEmployee(idx: number) {
  this.empFormArray.removeAt(idx);
}

Set Value in Form

FormGroup has two methods to set form values and that are setValue() and patchValue(). setValue() performs strict check and throw error if there is mismatch between existing form controls and the form controls which we are setting. If we use patchValue() then it will not throw error in case of mismatch of form controls. To set values in the form we can directly pass our object. Find the code snippet.
Using setValue()
this.teamForm.setValue(team); 
Using patchValue()
this.teamForm.patchValue(team); 
We can also set values form control wise. Find the code snippet.
this.teamForm.patchValue({
   teamName: team.teamName,
   teamManager: team.teamManager,
   teamDept: team.teamDept
}); 

Form Validation

To validate reactive form we need to use Validators class that has validation methods such as required(), email(), minLength(), maxLength() etc. Find the code snippet to validate a form field.
this.teamForm = this.formBuilder.group({
   teamName: ['', Validators.required ],
   teamManager: ['', Validators.minLength(15) ],
   ---------------
}); 
In HTML template, we can display validation message as following.
<p>Team Name : <input formControlName="teamName">
     <br/><label *ngIf="teamForm.get('teamName')?.invalid && teamForm.get('teamName')?.dirty" class = "error"> Team name is required. </label>
</p>

Fetch Form Data After Form Submit

We can fetch form data after form submit individually as well as complete data as an object of a class. To fetch form data individually, write code as follows.
let teamName = this.teamForm.get('teamName').value; 
To fetch complete form data in one go as an object of class, we can write code as follows.
let team: Team = this.teamForm.value; 
If we want to fetch data in JSON format, we can write code as follows.
let data = JSON.stringify(this.teamForm.value); 

Reset Form

To reset reactive form, FormGroup has reset() method. We need to call this method on the instance of FormGroup as following.
this.teamForm.reset(); 
While resetting form we can also set some default values to form controls as following.
this.teamForm.reset({
   teamName: 'Java Team',
   teamManager: 'Yogi'
}); 


Complete Example

app.component.ts
import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  template: `
           <app-team></app-team>
          `
})
export class AppComponent {
} 
employee.ts
export class Employee {
	empId = '';
	empName = ''; 
	skill = '';
} 
department.ts
export class Department {
	deptHead = ''; 
	deptName = '';
} 
team.ts
import { Employee } from './employee';
import { Department } from './department';

export class Team {
	teamName = '';
        teamManager = '';	
	teamDept = {} as Department;
	employees = [] as Employee[];
}  
team-data.ts
import { Team } from './team';

export const ALL_TEAMS: Team[] = [
 {
  "teamName":"Java Team",
  "teamManager":"Yogi",
  "teamDept":{
     "deptHead":"Modi",
     "deptName":"M Commerce"
   },
   "employees":[
      {
        "empId":"101",
        "empName":"Harish",
        "skill":"Java"
      },
      {
        "empId":"111",
        "empName":"Mohit",
        "skill":"Angular"
      }
     ]
  } 
];

export const ALL_SKILLS = [
   {name: 'Java', displayName: 'Java'},
   {name: 'Angular', displayName: 'Angular'},
   {name: 'Dot Net', displayName: 'Dot Net'}
]; 
team-management.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

import { Team } from './team';
import { ALL_TEAMS, ALL_SKILLS } from './team-data';

@Injectable()
export class TeamManagementService {
	getSkills() {
		return of(ALL_SKILLS);
	}
	getAllTeams(): Observable<Team[]> {
		return of(ALL_TEAMS);
	}
	getTeamByName(name: string): Observable<Team> {
		return this.getAllTeams().pipe(
			map(allTeams => allTeams.find(team => team.teamName === name) ?? new Team())
		);
	}
	saveTeam(team: Team) {
		console.log('------------TEAM------------');
		console.log('Team Name: ' + team.teamName);
		console.log('Team Manager: ' + team.teamManager);
		console.log('Dept Head: ' + team.teamDept.deptHead);
		console.log('Dept Name: ' + team.teamDept.deptName);
		console.log('----- Employee Detail -----');
		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('-------------------');
		}
	}
} 
team-management.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormArray, Validators, FormBuilder } from '@angular/forms';
import { of } from 'rxjs';

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

@Component({
	selector: 'app-team',
	templateUrl: './team-management.component.html'
})
export class TeamManagementComponent implements OnInit {
	teamForm = {} as FormGroup;
	formSubmitted = false;
	allSkills = of([] as any);
	constructor(
		private formBuilder: FormBuilder,
		private teamMngService: TeamManagementService) {
	}
	ngOnInit() {
		this.allSkills = this.teamMngService.getSkills();
		this.createTeamForm();
		this.addEmployee();
	}
	createTeamForm() {
		this.teamForm = this.formBuilder.group({
			teamName: ['', Validators.required],
			teamManager: '',
			teamDept: this.formBuilder.group(new Department()),
			employees: this.formBuilder.array([])
		});
	}
	get empFormArray(): FormArray {
		return this.teamForm.get('employees') as FormArray;
	}
	addEmployee() {
		let fg = this.formBuilder.group(new Employee());
		this.empFormArray.push(fg);
	}
	deleteEmployee(idx: number) {
		this.empFormArray.removeAt(idx);
	}
	loadTeam(name: string) {
		this.teamMngService.getTeamByName(name)
			.subscribe(team => {
				this.createFormWithDefaultData(team);
			});
	}
	createFormWithDefaultData(team: Team) {
		//this.teamForm.patchValue(team); 
		this.teamForm.patchValue({
			teamName: team.teamName,
			teamManager: team.teamManager,
			teamDept: team.teamDept
		});
		let employeeFormGroups = team.employees.map(employee => this.formBuilder.group(employee));
		let employeeFormArray = this.formBuilder.array(employeeFormGroups);
		this.teamForm.setControl('employees', employeeFormArray);
	}
	onFormSubmit() {
		let data = JSON.stringify(this.teamForm.value);
		console.log('-----Team in JSON Format-----');
		console.log(data);
		let team: Team = this.teamForm.value;
		this.teamMngService.saveTeam(team);
		this.formSubmitted = true;
		this.teamForm.reset();
	}
	resetTeamForm() {
		this.teamForm.reset({
			teamName: 'Java Team',
			teamManager: 'Yogi'
		});
	}
} 
team-management.component.html
<h3>Create New Team
  <button type="button" (click)="loadTeam('Java Team')"> Load Default Team </button>
  <button type="button" (click)="resetTeamForm()"> Reset </button>
</h3>
<div *ngIf="formSubmitted && teamForm.pristine" class="submitted"> Form submitted successfully. </div>
<div class="team">
  <form [formGroup]="teamForm" (ngSubmit)="onFormSubmit()">
    <p>Team Name : <input formControlName="teamName">
      <br /><label *ngIf="teamForm.get('teamName')?.invalid && teamForm.get('teamName')?.dirty" class="error"> Team name
        is required. </label>
    </p>
    <p>Team Manager : <input formControlName="teamManager"></p>

    <b>Department :</b><br>
    <div formGroupName="teamDept" class="department">
      <p>Department Head : <input formControlName="deptHead"></p>
      <p>Department Name : <input formControlName="deptName"></p>
    </div>
    <div class="all-emp">
      <b> Employees in Team :</b><br><br>
      <div formArrayName="employees">
        <div *ngFor="let emp of empFormArray.controls; let idx = index" [formGroupName]="idx" class="employee">
          <p> <b>Employee : {{idx + 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 [disabled]="teamForm.invalid">SUBMIT</button>
  </form>
</div> 
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 { } 
styles.css
.employee {
	border: 2px solid blue;
	width: 275px;
}
.department {
	border: 2px solid blue;
	width: 275px;
}
.team {
	border: 3px solid black;
	width: 300px;
}
.all-emp {
	border: 3px solid black;
	width: 275px;	
}
.error{
        color: red;
} 
.submitted{
        color: green;
        font-size: 20px;
} 

Run Application

To run the demo application, find following 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 FormBuilder Example

References

FormBuilder
Reactive Forms

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us