FormGroup in Angular
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.
Contents
Using FormGroup
To use aFormGroup
, 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') });
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>
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' });
setValue()
otherwise it will throw error.
2. Using
patchValue()
this.userForm.patchValue({name: 'Mahesh'});
patchValue()
then it is not necessary to mention all form controls.
FormGroup Get Value
SupposeuserForm
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
this.userForm.value
FormGroup reset()
To reset the form we need to callreset()
method on FormGroup
instance. Suppose userForm
is the instance of FormGroup
then we create a method as given below.
resetForm() { this.userForm.reset(); }
<button type="button" (click) = "resetForm()">Reset</button>
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 usingsubscribe()
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); }
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 aFormGroup
, first we will create an instance of FormControl
within a FormGroup
.
userForm = new FormGroup({ -------------- -------------- gender: new FormControl('male') });
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>
get()
method.
this.userForm.get('gender').value
FormGroup with Select Element
Here we will provide how to use select element withFormGroup
. 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'} ];
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) });
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>
get()
method.
this.userForm.get('profile').value;
FormGroup Validation
To validate a form control inFormGroup
, 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) });
get userName(): any { return this.userForm.get('name'); }
userName.invalid
. We can also get validity state directly using instance of FormGroup
.
userForm.get('age').invalid
<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>
country: new FormControl({value: 'India', disabled: true})
Nested FormGroup
AFormGroup
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') }) });
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>
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;
FormGroup
.
addressFG.value addressFG.valid
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() ]) });
<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>
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); }
FormArray
as given below.
for(let i = 0; i < this.users.length; i++) { console.log(this.users.at(i).value); }
FormArray
, we can write code as given below.
this.userForm.value this.userForm.valid
Complete Example
formgroup.component.tsimport { 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); } }
<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>
.error{ color: red; font-size: 20px; } .success{ color: green; font-size: 20px; }
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 { }
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.
References
FormControlFormGroup
FormArray