In this lesson we will learn about Reactive Forms in Angular. Reactive forms ( also known as Model-driven forms) are one of the two ways to build Angular forms. Please read my previous lesson of Template driven forms in Angular.
To build reactive forms, first, we need to import ReactiveFormsModule
. We then create the Form Model in component class using Form Group
, Form Control
& FormArrays
. Next, we will create the HTML form template and bind it to the Form Model.
What are Reactive Forms?
Reactive forms are forms where we define the structure of the form in the component class. i.e. we create the form model with Form Groups
, Form Controls
, and FormArrays
. We also define the validation rules in the component class. Then, we bind it to the HTML form in the template.
Reactive Forms Example
Let’s first create a sample Angular application using command ng new reactive-forms
. Here “reactive-forms” is our project name. We set Routing as Yes and
Import ReactiveFormsModule
To work with Reactive forms, we must import the ReactiveFormsModule
. We usually import it in root module or in a shared module. The ReactiveFormsModule
contains all the form directives and constructs for working with angular reactive forms.
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './components/reactive-form/reactive-form.component';
import { TemplateDrivenComponent } from './components/template-driven/template-driven.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatCardModule } from "@angular/material/card";
import { MatButtonModule } from "@angular/material/button";
@NgModule({
declarations: [
AppComponent,
ReactiveFormComponent,
TemplateDrivenComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
BrowserAnimationsModule,
MatCardModule,
MatButtonModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Creating the Form Model
In the Reactive Forms approach, it is our responsibility to build model using FormGroup
, FormControl
& FormArray
.
The FormGroup
, FormControl
& FormArray
are the three building blocks of the Angular Forms. We learned about them in the Angular Forms Tutorial. FormControl
encapsulates the state of a single form element in our form. It stores the value and state of the form element and helps us to interact with them using properties & methods.
FormGroup
represents a collection of form controls. It can also contain other FormGroups and FormArrays. In fact, an angular form is a FormGroup
.
The FormGroup
is created with the following syntax
contactForm = new FormGroup({})
The FormGroup
takes 3 arguments. a collection of a child controls (which can be FormControl, FormArray, or another FormGroup), a validator
, and an asynchronous validator
. The validators are optional.
Adding the Child Controls
The next step is to add the child controls to the contactForm
. The first argument to FormGroup
is the collection of controls. The Controls can be FormControl
, FormArray
or another FormGroup
. It can be done by creating a new instance for FormControl (or FormGroup or FormArray).
contactForm = new FormGroup({
firstname: new FormControl(),
lastname: new FormControl(),
email: new FormControl(),
gender: new FormControl(),
isMarried: new FormControl(),
country: new FormControl()
})
HTML Form
The next task is to build an HTML form, We enclose it in a <form>
tag. We have included two text inputs (FirstName & LastName), an email field, a radio button (gender), a checkbox (isMarried), and a select list (country). These are simple HTML Form elements.
<form>
<p>
<label for="firstname">First Name </label>
<input type="text" id="firstname" name="firstname">
</p>
<p>
<label for="lastname">Last Name </label>
<input type="text" id="lastname" name="lastname">
</p>
<p>
<label for="email">Email </label>
<input type="text" id="email" name="email">
</p>
<p>
<label for="gender">Geneder </label>
<input type="radio" value="male" id="gender" name="gender"> Male
<input type="radio" value="female" id="gender" name="gender"> Female
</p>
<p>
<label for="isMarried">Married </label>
<input type="checkbox" id="isMarried" name="isMarried">
</p>
<p>
<label for="country">country </label>
<select id="country" name="country">
<option value="1">India</option>
<option value="2">USA</option>
<option value="3">England</option>
<option value="4">Singapore</option>
</select>
</p>
<p>
<button type="submit">Submit</button>
</p>
</form>
Binding the template to the model
Now we need to associate our model with the above HTML Template. We need to tell angular that we have a model for the form.
<form [formGroup]="contactForm">
Next, we need to bind each form field to an instance of the FormControl
models. We use the FormControlName
directive for this. We add this directive to every form field element in our form. The value is set to the name of the corresponding FormControl
instance in the component class.
<input type="text" id="firstname" name="firstname" formControlName="firstname">
<input type="text" id="lastname" name="lastname" formControlName="lastname">
Submit form
We submit the form data to the component using the Angular directive named ngSubmit
. Note that we already have a submit
button in our form. The ngSubmit
directive binds itself to the click event of the submit
button. We are using event binding (parentheses) to bind ngSubmit
to OnSubmit
method. When the user clicks on the submit
button ngSubmit
invokes the OnSubmit
method on the Component class.
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()">
Final HTML template look like below,
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()">
<p>
<label for="firstname">First Name </label>
<input type="text" id="firstname" name="firstname" formControlName="firstname">
</p>
<p>
<label for="lastname">Last Name </label>
<input type="text" id="lastname" name="lastname" formControlName="lastname">
</p>
<p>
<label for="email">Email </label>
<input type="text" id="email" name="email" formControlName="email">
</p>
<p>
<label for="gender">Geneder </label>
<input type="radio" value="male" id="gender" name="gender" formControlName="gender"> Male
<input type="radio" value="female" id="gender" name="gender" formControlName="gender"> Female
</p>
<p>
<label for="isMarried">Married </label>
<input type="checkbox" id="isMarried" name="isMarried" formControlName="isMarried">
</p>
<p>
<label for="country">country </label>
<select id="country" name="country" formControlName="country">
<option value="1">India</option>
<option value="2">USA</option>
<option value="3">England</option>
<option value="4">Singapore</option>
</select>
</p>
<p>
<button type="submit">Submit</button>
</p>
</form>
Receive the data in the Component class
The last step is to receive the form data in the component class. All we need to do is to create the onSubmit
method in our component class.
onSubmit() {
console.log(this.contactForm.value);
}
We are using the console.log(this.contactForm.value)
to send the value of our form data to the console window.
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html',
styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent implements OnInit {
myreactiveForm!: FormGroup;
contactForm = new FormGroup({
firstname: new FormControl(),
lastname: new FormControl(),
email: new FormControl(),
gender: new FormControl(),
isMarried: new FormControl(),
country: new FormControl()
});
ngOnInit(): void {
// create an instance of form group
// for the object passed, the key identifies the control name, the value identifies the actual control
// the Validators provides validator functions that need to be applied to the control value
this.myreactiveForm = new FormGroup({
'name': new FormControl('', [Validators.required]),
'emailAddress': new FormControl('', [Validators.required, Validators.email]),
'age': new FormControl('', [Validators.required, Validators.pattern('^[0-9]+$')])
});
}
onSubmit() {
console.log(this.myreactiveForm.value);
}
}
FormControl
A FormControl
takes 3 arguments. a default value, a validator, and an asynchronous validator. All of them are optional.
Default Value
You can pass a default value either as a string or as an object of key-value pair. When you pass an object you can set both the value and the whether or not the control is disabled.
//Setting Default value as string
firstname= new FormControl('John');
//Setting Default value & disabled state as object
firstname: new FormControl({value: 'John', disabled: true}),
Sync Validator
The second parameter is an array of sync Validators. Angular has some built-in Validators such as required and minLength etc.
firstname: new FormControl('', [Validators.required,Validators.minLength(10)]),
Asynchronous validator
The third argument is the Async Validator. The syntax of Async Validators is similar to Sync Validators.
Grouping the controls using FormGroup
We can group various FormControls together. For Example fields such as street, city, country and Pincode each will have their own FormControl but can be grouped together as an address FormGroup.
contactForm = new FormGroup({
firstname: new FormControl(),
lastname: new FormControl(),
email: new FormControl(),
gender: new FormControl(),
isMarried: new FormControl(),
address:new FormGroup({
city: new FormControl(),
street: new FormControl(),
pincode:new FormControl(),
country: new FormControl(),
})
})
Conclusion
In this lesson we will learn about Reactive Forms in Angular. Reactive forms ( also known as Model-driven forms) are one of the two ways to build Angular forms.
Leave behind your valuable queries and suggestions in the comment section below. Also, if you think this article helps you, do not forget to share this with your developer community. Happy Coding 🙂
Jayant Tripathy
Coder, Blogger, YouTuberA passionate developer keep focus on learning and working on new technology.