FormGroup in Angular

Written by: Arvind Rai,
Last updated:
July 21, 2020
This page will walk through Angular FormGroup example. The FormGroup takes part in creating reactive form. FormGroup is used with FormControl and FormArray. The role of FormGroup is to track the value and validation state of form control. In our example we will create a form that will include <input> and <select> element. We will see how to instantiate FormGroup and how to set and access values in FormGroup. We will also validate the form. First let us understand the angular classes and directive that we will use in our example.

FormControl:It is a class that tracks the value and validation state of a form control.
FormGroup: It is a class that tracks the value and validity state of a group of FormControl.
FormArray: It is a class that tracks the value and validity state of array of FormControl, FormGroup and FormArray.
FormControlName: It is a directive that syncs a FormControl in an existing FormGroup to a form control by name.
FormGroupDirective: It is a directive that binds an existing FormGroup to a DOM element.
FormGroupName: It is a directive that syncs a nested FormGroup to a DOM element.
FormArrayName: It is a directive that syncs a nested FormArray to a DOM element.

Now we will discuss the complete example step by step.

Using FormGroup

To use a FormGroup, find the following steps.
Step-1: Import ReactiveFormsModule from @angular/forms library in our application module and configure ReactiveFormsModule in imports metadata of @NgModule as following.
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

@NgModule({
  imports: [     
        BrowserModule,
	ReactiveFormsModule
  ],
-------------
-------------
})
export class AppModule { } 
ReactiveFormsModule enables using FormControl, FormGroup and FormArray in our application.
Step-2: Create an instance of FormGroup with the instances of FormControl.
userForm = new FormGroup({
     name: new FormControl(),
     age: new FormControl('20')
}); 
If we want to initialize a default value, we can pass it as an argument in FormControl. In the above code age form control will be pre-populated with the value 20.
Step-3: Now we create a <form> element in our HTML template. The selector of FormGroupDirective is [formGroup]. We will bind FormGroup instance userForm with the selector [formGroup] and FormControl instances are bound to form control using FormControlName directive. Now find the code.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  Name: <input formControlName="name"  placeholder="Enter Name">
  Age: <input formControlName="age"  placeholder="Enter Age">
  <button type="submit">Submit</button> 
</form> 
When we click on submit button, form will be submitted and ngSubmit will call our method onFormSubmit.
Step-4: Create a method that will be called when form is submitted.
onFormSubmit(): void {
    console.log('Name:' + this.userForm.get('name').value);
} 

FormGroup setValue() and patchValue()

setValue() and patchValue() both are used to set values to FormGroup instance at run time. The difference between them is that when we use setValue(), we have to set all form controls in our FormGroup and when we use patchValue() then selected form control can be set. Find the example.
Suppose we are creating FormGroup as following.
userForm = new FormGroup({
     name: new FormControl(),
     age: new FormControl()
}); 

1. Using setValue()
this.userForm.setValue({name: 'Mahesh', age: '20' }); 
It is necessary to mention all from controls in setValue() otherwise it will throw error.
2. Using patchValue()
this.userForm.patchValue({name: 'Mahesh'}); 
When we use patchValue() then it is not necessary to mention all form controls.

FormGroup Get Value

Suppose userForm is the instance of FormGroup. To get the value of form control named as name after form submit, we need to write the code as below.
this.userForm.get('name').value 
If we want to get all values of the form then we can write code as given below.
this.userForm.value 

FormGroup reset()

To reset the form we need to call reset() method on FormGroup instance. Suppose userForm is the instance of FormGroup then we create a method as given below.
resetForm() { 
    this.userForm.reset();
} 
We can call the above method using a button as following.
<button type="button" (click) = "resetForm()">Reset</button> 
If we want to reset form with some default values, then assign the default values with form control name of the form.
resetForm() { 
   userForm.reset({
      name: 'Mahesh',
      age: 20
   });
} 

FormGroup valueChanges() and statusChanges()

To track the value changes and status changes of a form control we need to listen them using subscribe() method. Find the code.
usrNameChanges: string;
usrNameStatus: string;
ngAfterViewInit(): void {
    this.userForm.get('name').valueChanges.subscribe(data => this.usrNameChanges = data);
    this.userForm.get('name').statusChanges.subscribe(data => this.usrNameStatus = data);
} 
In the above code name is the name of form control. Now we can use value changes and status changes to display on UI.
<p *ngIf="usrNameChanges">Name: <b>{{usrNameChanges}}</b> </p>
<p *ngIf="usrNameStatus">Name Status: <b>{{usrNameStatus}}</b> </p> 

FormGroup with Radio Button

To use radio button in a FormGroup, first we will create an instance of FormControl within a FormGroup.
userForm = new FormGroup({  
   --------------
   --------------
   gender: new FormControl('male')
}); 
We are creating radio button to select gender while filling the form. We can pass the initial value while instantiating FormControl. Now we will create the form in HTML template as given below.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  ---------------------------
  ---------------------------
  <div>
       Select Gender:
       <input type="radio" formControlName="gender" value="male"> Male
       <input type="radio" formControlName="gender" value="female" > Female
  </div>
</form> 
We can access its value using get() method.
this.userForm.get('gender').value

FormGroup with Select Element

Here we will provide how to use select element with FormGroup. First of all we will create an array of elements that will contain key and value for select element. Find the array given below.
profiles = [
    {name: 'Developer', shortName: 'dev'},
    {name: 'Manager', shortName: 'man'},
    {name: 'Director', shortName: 'dir'}
]; 
We will use the value of name in our array to display data in select element and the value of shortName will be assigned to value attribute of <option> element.
Now to use select element in a FormGroup, first we will create an instance of FormControl within a FormGroup.
userForm = new FormGroup({  
   --------------
   --------------
   profile: new FormControl(this.profiles[0].shortName)
}); 
We can pass the initial selected value while instantiating FormControl. In the above code first element of array profiles will be selected as default. Now we will create the form in HTML template as given below.
<div>
  Select Profile:
  <select formControlName="profile">
	<option *ngFor="let pf of profiles" [ngValue]="pf.shortName">
		  {{ pf.name }}
	</option>
  </select>
</div> 
We can access its value using get() method.
this.userForm.get('profile').value; 

FormGroup Validation

To validate a form control in FormGroup, angular provides Validators class. We can use it to enable validation in form control as given below.
userForm = new FormGroup({
   name: new FormControl('', [Validators.required, Validators.maxLength(10)]),
   age: new FormControl('', Validators.required)
});
To check validity of form control, we can write a method for a form control as given below.
get userName(): any {
    return this.userForm.get('name');
} 
Now in HTML template we can access validity state as userName.invalid. We can also get validity state directly using instance of FormGroup.
userForm.get('age').invalid 
Now find the sample HTML template code of form.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  <div>
	Name: <input formControlName="name"  placeholder="Enter Name">
	<label *ngIf="userName.invalid" [ngClass] = "'error'"> Name is required with 10 max character. </label>
  </div>
  <div> 
	Age: <input formControlName="age"  placeholder="Enter Age">
	<label *ngIf="userForm.get('age').invalid" [ngClass] = "'error'"> Age is required. </label>
  </div>
  <div> 
       <button type="submit">Submit</button>
  </div>
</form> 
If we want to disable a field with pre-populated value, we can instantiate form control as given below.
country: new FormControl({value: 'India', disabled: true}) 

Nested FormGroup

A FormGroup instance can contain a nested FormGroup instance. The use of nested FormGroup is that if we want to get validity state of only few form controls and not all, then we can put those form controls in a nested FormGroup as given below.
userForm = new FormGroup({
	name: new FormControl('', [Validators.required, Validators.maxLength(10)]),
	address: new FormGroup({
	    houseNumber: new FormControl('', Validators.required),
	    city: new FormControl('Noida')
        })
}); 
In the above code address is the nested FormGroup inside userForm FormGroup. To use nested FormGroup in form element in HTML template, angular provides FormGroupName directive that syncs a nested FormGroup to a DOM element. Find the code.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  <div>
	Name: <input formControlName="name"  placeholder="Enter Name">
	<label *ngIf="userName.invalid" [ngClass] = "'error'"> Name is required with 10 max character. </label>
  </div>
  <div formGroupName="address">
	  <div>
		House Number: <input formControlName="houseNumber"  placeholder="Enter House Number">
		<label *ngIf="userForm.get('address').get('houseNumber').invalid" [ngClass] = "'error'"> House Number is required. </label>
	  </div>  
	  <div>
		City: <input formControlName="city"  placeholder="Enter City">
	  </div>
	  <div>
		Country: <input formControlName="country">
	  </div>
  </div>
  <div>
     <button type="submit">Submit</button>
  </div>
</form> 
Get value of nested FormGroup

First we need to get nested FormGroup by parent FormGroup and call the get() method.
let addressFG = this.userForm.get('address');
addressFG.get('houseNumber').value; 
Find the code snippet to get the value and validity state of a nested FormGroup.
addressFG.value
addressFG.valid 
Set value in nested FormGroup

To set the value in form controls of nested FormGroup, we can write the code as given below.
setCountry() { 
    this.userForm.get('address').get('country').setValue('India');
}    
setDefaultValue() { 
    this.userForm.patchValue({name: 'Mahesh', address: {city:'Noida', country: 'India'} });
}

Nested FormArray

FormArray is used to add and remove form elements at runtime. We can use a FormArray inside a FormGroup as given below.
userForm = new FormGroup({
       name: new FormControl('', [Validators.required, Validators.maxLength(10)]),
       users: new FormArray([
          new FormControl('Mahesh'),
          new FormControl()
       ])
}); 
We will write code in form as given below.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  <div>
	Name: <input formControlName="name"  placeholder="Enter Name">
	<label *ngIf="userName.invalid" [ngClass] = "'error'"> Name is required with 10 max character. </label>
  </div>
  <div formArrayName="users">
	<div *ngFor="let user of users.controls; index as idx">
	  <input [formControlName]="idx" placeholder="Enter User Name">
	  <button type="button" (click)="deleteUserField(idx)">Delete</button>
	</div>
  </div>
  <button type="button" (click)="addUserField()">Add More User</button>  
  <button type="submit">Submit</button>
</form> 
To add form controls in FormArray at runtime, the instance of FormArray will call push() method that accepts new instance of FormControl and to remove form control, it will call removeAt() method that accepts index of form control to be removed. We can write the methods as given below.
addUserField() { 
     this.users.push(new FormControl()); 
}
deleteUserField(index: number) {
     this.users.removeAt(index);
} 
On the submit of form, we can access the values of individual form control of FormArray as given below.
for(let i = 0; i < this.users.length; i++) {
   console.log(this.users.at(i).value);
} 
To get the value and validity state of FormArray, we can write code as given below.
this.userForm.value 
this.userForm.valid 

Complete Example

formgroup.component.ts
import { Component, AfterViewInit } from '@angular/core';
import {FormControl, FormGroup, FormArray, Validators} from '@angular/forms';

@Component({
   selector: 'app-form-group',
   templateUrl: 'formgroup.component.html',
   styleUrls: ['formgroup.component.css']
})
export class FormGroupDemoComponent implements AfterViewInit { 
  usrNameChanges: string;
  usrNameStatus: string;
  formSubmitted = false;
  profiles = [
    {name: 'Developer', shortName: 'dev'},
    {name: 'Manager', shortName: 'man'},
    {name: 'Director', shortName: 'dir'}
  ];
  userForm = new FormGroup({
	name: new FormControl('', [Validators.required, Validators.maxLength(10)]),
	age: new FormControl('', Validators.required),
	address: new FormGroup({
	    houseNumber: new FormControl('', Validators.required),
	    city: new FormControl('Noida'),
    	    country: new FormControl({value: 'India', disabled: true})
        }),
	gender: new FormControl('male'),
	profile: new FormControl(this.profiles[1].shortName),
	users: new FormArray([
           new FormControl('Mahesh'),
           new FormControl('Krishna'),
	   new FormControl()
        ])
  });
  get userName(): any {
    return this.userForm.get('name');
  }
  ngAfterViewInit(): void {
        this.userForm.get('name').valueChanges.subscribe(data => this.usrNameChanges = data);
	this.userForm.get('name').statusChanges.subscribe(data => this.usrNameStatus = data);
  }  
  onFormSubmit(): void {
    this.formSubmitted = true;
    if(this.userForm.valid) {
	this.logData();
	this.resetForm();
    } else {
	this.formSubmitted = false;
    }
  }
  resetForm() { 
    this.userForm.reset();
  }  
  setDefaultValue() { 
    this.userForm.patchValue({name: 'Mahesh', gender: 'male', profile: this.profiles[2].shortName,
                            	address: {city:'Noida', country: 'India'} });
  }
  setAge() { 
    this.userForm.get('age').setValue('20');
  }  
  setCountry() { 
    this.userForm.get('address').get('country').setValue('India');
  }    
  get users(): FormArray { 
    return this.userForm.get('users') as FormArray; 
  }
  addUserField() { 
    this.users.push(new FormControl()); 
  }
  deleteUserField(index: number) {
    this.users.removeAt(index);
  }
  logData() {
	 console.log('Name:' + this.userForm.get('name').value);
	 console.log('Age:' + this.userForm.get('age').value);	 
	 console.log('Gender:'+ this.userForm.get('gender').value);	 
	 console.log('Profile:'+this.userForm.get('profile').value);	 

	 //print address
	 let addressFG = this.userForm.get('address');
	 console.log('House Number: ' + addressFG.get('houseNumber').value);	 
	 console.log('City:' + addressFG.get('city').value);
	 console.log('Country:' + addressFG.get('country').value);
	
	//Iterate FormArray
	 for(let i = 0; i < this.users.length; i++) {
	   console.log(this.users.at(i).value);
	 }
         // Gives complete address
	 console.log(addressFG.value); 
         //Checks address validation	 
	 console.log(addressFG.valid); 
         // Gives complete FormArray data	 
	 console.log(this.users.value); 
         //Checks FormArray validation	 	
	 console.log(this.users.valid); 	 
         // Gives Complete form data	 	 
	 console.log(this.userForm.value); 
         // checks Complete form validation	 	 
	 console.log(this.userForm.valid);	 
  }
} 
formgroup.component.html
<h3> FormGroup Example </h3>
<div *ngIf="userForm.invalid && !formSubmitted" [ngClass] = "'error'"> Form not validated. </div>
<div *ngIf="formSubmitted" [ngClass] = "'success'"> Form submitted successfully. </div> <br/>
<div> 
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
  <div>
	Name: <input formControlName="name"  placeholder="Enter Name">
	<label *ngIf="userName.invalid" [ngClass] = "'error'"> Name is required with 10 max character. </label>
  </div>
  <div> 
	Age: <input formControlName="age"  placeholder="Enter Age">
	<label *ngIf="userForm.get('age').invalid" [ngClass] = "'error'"> Age is required. </label>
  </div>
  <div formGroupName="address">
	  <div>
		House Number: <input formControlName="houseNumber"  placeholder="Enter House Number">
		<label *ngIf="userForm.get('address').get('houseNumber').invalid" [ngClass] = "'error'"> House Number is required. </label>
	  </div>  
	  <div>
		City: <input formControlName="city"  placeholder="Enter City">
	  </div>
	  <div>
		Country: <input formControlName="country">
	  </div>
  </div>
  <div>
	  Select Gender:
	  <input type="radio" formControlName="gender" value="male"> Male
	  <input type="radio" formControlName="gender" value="female" > Female
  </div>  
  <div>
	  Select Profile:
	  <select formControlName="profile">
		<option *ngFor="let pf of profiles" [ngValue]="pf.shortName">
			  {{ pf.name }}
		</option>
	  </select>
  </div>
  <br/>
  <div formArrayName="users">
	<div *ngFor="let user of users.controls; index as idx">
	  <input [formControlName]="idx" placeholder="Enter User Name">
	  <button type="button" (click)="deleteUserField(idx)">Delete</button>
	</div>
  </div>
  <button type="button" (click)="addUserField()">Add More User</button>  
  <br/><br/>  
  <div>
	<button type="submit">Submit</button>
	<button type="button" (click) = "setAge()">Set Age</button>
	<button type="button" (click) = "setCountry()">Set Country</button>
	<button type="button" (click) = "setDefaultValue()">Set Defaults</button>	
	<button type="button" (click) = "resetForm()">Reset to Blank</button>	
  </div>
</form>
<div>
<p *ngIf="usrNameChanges">Name: <b>{{usrNameChanges}}</b> </p>
<p *ngIf="usrNameStatus">Name Status: <b>{{usrNameStatus}}</b> </p> 
formgroup.component.css
.error{
    color: red;
    font-size: 20px;
}
.success{
    color: green;
    font-size: 20px;
} 
app.component.ts
import { Component } from '@angular/core';
import {FormControl, Validators} from '@angular/forms';

@Component({
   selector: 'app-root',
   template: `
		<app-form-group></app-form-group>
	     `
})
export class AppComponent { 
} 
app.module.ts
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }  from './app.component';
import { FormGroupDemoComponent }  from './formgroup.component';

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

Run Application

To run the 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. Now access the URL http://localhost:4200
Find the print screen of the output.
Angular FormGroup Example

References

FormControl
FormGroup
FormArray

Download Source Code

Join the Newsletter

(Subscribe to get our latest content directly into your inbox)

WRITTEN BY
ARVIND RAI
ARVIND RAI









©2024 concretepage.com | Privacy Policy | Contact Us