Reactive Forms in Angular
5 min readMay 3, 2021
Setup
app.module.ts
- Import ReactiveFormsModule module in app.module.ts
2. Provide that ReactiveFormsModule inside @NgModule : imports
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})export class AppModule { }
1. FormControl: Normal One Input Field
app.component.html
Enter your name: <input type="text" [formControl]="personName">
<div *ngIf='personName.value != ""'>
<hr>Hello {{personName.value}}
</div>
<hr><button (click)="onReset()">Reset</button>
app.component.ts
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']})export class AppComponent {
personName: FormControl = new FormControl(''); onReset(): void{
this.personName.setValue("");
//if you want to provide default value then you can assign at here
}
}
2. FormGroup: group your Form-controls
app.component.html
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<label> Username </label>
<input type="text" formControlName="name" />
<label> Password </label>
<input type="password" formControlName="password" />
<br><input type="submit" value="SAVE">
</form>
- [formGroup]: used to specify the formGroup name
- formControlName=”name”: used to specify the formControl Name, that is sub-part of formGroup
- (ngSubmit)=”onSubmit()”: onSubmit() function is going to execute when user submit this form
app.component.ts
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})export class AppComponent { // FormGroup
loginForm: FormGroup = new FormGroup({
//create a FormControl for each input
name: new FormControl(''),
password: new FormControl(''),
}); //handle the on submit
onSubmit() {
console.warn(this.loginForm.value);
console.log('Name is ' + this.loginForm.value.name);
console.log('Password is ' + this.loginForm.value.password);
}
}
Check the Output
3. Nested FormGroup
app.module.ts : formGroupObject
profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
//for inner group
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl(''),
}),
});
app.component.html
<!-- outer group -->
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>First Name:</label>
<input type="text" formControlName="firstName"><br>
<label>Last Name:</label>
<input type="text" formControlName="lastName"><br>
<!-- inner group -->
<div formGroupName="address">
<h3>Address</h3>
<label>Street:</label>
<input type="text" formControlName="street"><br>
<label>City:</label>
<input type="text" formControlName="city"><br>
<label>State:</label>
<input type="text" formControlName="state"><br>
<label>Zip Code:</label>
<input type="text" formControlName="zip"><br>
</div>
<hr>
<button type="submit">Submit</button>
</form>
4. FormBuilder
FormBuilder will automatically create Form Controls, no need to create Form Controls.
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})export class AppComponent {
loginForm: FormGroup = this.fb.group({
name: ['Default Name'],
password: [''],
}); constructor(private fb: FormBuilder) {} //handle the on submit
onSubmit() {
console.warn(this.loginForm.value);
console.log('Name is ' + this.loginForm.value.name);
console.log('Password is ' + this.loginForm.value.password);
}
}
We only need to change TS file, no need to change HTML file.
If you are using the nested form group then you can write like this
5. Validations
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, } from '@angular/forms';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})export class AppComponent {
loginForm: FormGroup = this.fb.group({
name: ['', [Validators.required]],
password: ['', [
Validators.required,
Validators.minLength(3)
]],
}); get name() {
return this.loginForm.get('name');
} get password() {
return this.loginForm.get('password');
} constructor(private fb: FormBuilder) {} onSubmit() {
console.warn(this.loginForm.value);
console.log('Name is ' + this.loginForm.value.name);
console.log('Password is ' + this.loginForm.value.password);
}
}
app.component.html
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<label> Username </label> <input type="text" formControlName="name" />
<div *ngIf="name.invalid && name.touched">
<small *ngIf="name.hasError('required')"> Name is required </small>
</div> <label> Password </label> <input type="password" formControlName="password" />
<div *ngIf="password.invalid && password.touched">
<small *ngIf="password.hasError('required')"> Password is required </small>
<small *ngIf="password.hasError('minlength')"> Min 3 char password</small>
</div> <br /><input type="submit" [disabled]="loginForm.invalid" value="SAVE" />
</form>
- Display the error if input is touched and there is error, using ngIf
- name field there is only one error, whereas password has two error.
- Here, we are directly using the password, but for that we have already created the getter for each field
- [disabled]=”loginForm.invalid”, this will disable submit button if there is an Validation constraint fail.
6. Provide styles on error
Install bootstrap
npm i bootstrap
src/style.css
@import "~bootstrap/dist/css/bootstrap.min.css";
app.component.html
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" class="container">' <!-- Input Field for User name -->
<div class="form-group">
<label> Username </label>
<input class="form-control" type="text" formControlName="name" />
<!-- Error messages for User name -->
<div *ngIf="name.invalid && name.touched" class="text-danger"> <small *ngIf="name.hasError('required')"> Name is required </small>
</div>
</div><!-- Input Field for Password-->
<div>
<label> Password </label>
<input class="form-control" type="password" formControlName="password"/>
<!-- Error messages password-->
<div *ngIf="password.invalid && password.touched" class="text-danger">
<small *ngIf="password.hasError('required')">Password is required</small>
<small *ngIf="password.hasError('minlength')">Min 3 char password</small>
</div>
</div>
<br />
<input type="submit" [disabled]="loginForm.invalid" value="SAVE" />
</form>
Provide more styles on error:
app.component.css
.form-control.ng-invalid.ng-touched{
border: 1px solid red;
border-left: 3px solid red;
}.form-control.ng-valid.ng-touched{
border: 3px solid green;
}