Reactive Forms in Angular

Bhavik Vashi
5 min readMay 3, 2021

--

Setup

app.module.ts

  1. 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>
  1. [formGroup]: used to specify the formGroup name
  2. formControlName=”name”: used to specify the formControl Name, that is sub-part of formGroup
  3. (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

UI User Input
Data of User Input

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);
}
}
Changes

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>
  1. Display the error if input is touched and there is error, using ngIf
  2. name field there is only one error, whereas password has two error.
  3. Here, we are directly using the password, but for that we have already created the getter for each field
  4. [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;
}

--

--

No responses yet