Angular 8/9 Reactive Forms Validation with Angular Material 8

By Digamber Rawat Last updated on
We are going to create an Angular 8/9 Reactive form with Angular Material forms. We’ll be using ReactiveFormsModule API to build and validate Reactive forms. As we know, there are 2 types of Form types offered by Angular 8/9.

Angular 8/9 Form Types:

  • Template Driven Form
  • Reactive Forms

In this tutorial, we’ll be using Reactive Forms to create and validate forms. Our focus will be on common Reactive Forms API: FormControl, FormGroup, FormaArray, and FormBuilder.

Reactive Forms is an easy to use service, and Reactive forms are used to handle more complex data.

#01 – Setup Angular Project

To work with Reactive Forms in Angular 8/9 we must have a basic project setup. Follow the process to setup the project.

ng new angular8-reactive-forms

# ? Would you like to add Angular routing? = Yes
# ? Which stylesheet format would you like to use? = CSS

Ge into the project’s folder.

cd angular8-reactive-forms

#02 – Implement Angular Material UI Library in Angular 8/9 Project.

To create reactive forms demo, We’ll be using Angular material ui library. Angular material offers lots of beautiful components we’ll be using Angular material library’s forms component to create and validate Reactive forms.

Run the cmd to setup Angular material library.

ng add @angular/material

Select the Angular material theme from the options:

? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink

❯ Indigo/Pink        [ Preview: https://material.angular.io?theme=indigo-pink ] 
  Deep Purple/Amber  [ Preview: https://material.angular.io?theme=deeppurple-amber ] 
  Pink/Blue Grey     [ Preview: https://material.angular.io?theme=pink-bluegrey ] 
  Purple/Green       [ Preview: https://material.angular.io?theme=purple-green ]

Select yes and hit enter.

# Set up HammerJS for gesture recognition? (Y/n) = Y
# ? Set up browser animations for Angular Material? (Y/n) = Y

Create material.module.ts file in app folder and paste the below code.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { MatBadgeModule } from '@angular/material/badge';
import { MatButtonModule } from '@angular/material/button';
import { MatChipsModule } from '@angular/material/chips';
import { MatNativeDateModule } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';

@NgModule({
   imports: [
      CommonModule,
      MatButtonModule,
      MatToolbarModule,
      MatIconModule,
      MatSidenavModule,
      MatBadgeModule,
      MatListModule,
      MatGridListModule,
      MatFormFieldModule,
      MatInputModule,
      MatSelectModule,
      MatRadioModule,
      MatDatepickerModule,
      MatNativeDateModule,
      MatChipsModule,
      MatTooltipModule,
      MatTableModule,
      MatPaginatorModule
   ],
   exports: [
      MatButtonModule,
      MatToolbarModule,
      MatIconModule,
      MatSidenavModule,
      MatBadgeModule,
      MatListModule,
      MatGridListModule,
      MatInputModule,
      MatFormFieldModule,
      MatSelectModule,
      MatRadioModule,
      MatDatepickerModule,
      MatChipsModule,
      MatTooltipModule,
      MatTableModule,
      MatPaginatorModule
   ],
   providers: [
      MatDatepickerModule,
   ]
})

export class AngularMaterialModule { }

Then go to app.module.ts file and paste the following code to enable material.module.ts in Angular app.

/* Angular material */
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './material.module';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

@NgModule({
  declarations: [...],
  imports: [
    BrowserAnimationsModule,
    AngularMaterialModule,
  ],
  providers: [...],
  bootstrap: [...],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})

export class AppModule { }

Now we’ll add Angular material 8 theme and Angular material icons in our project.

Go to src > index.html file and add the following code in the head section.

<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

Go to src > styles.css file and add the following code.

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

html,body{height:100%;}
body{margin:0;font-family:Roboto, "Helvetica Neue", sans-serif;}
form{width:420px;margin:35px auto 100px;display:block;float:none;}
.mat-form-field{width:100%;}
.misc-bottom-padding{margin:8px 0 20px;}
.misc-bottom-padding mat-label{margin-right:15px;}
.mat-radio-label{margin:0 15px 0 0;}
.title-center{margin:0 auto;}
.button-wrapper{margin-top:10px;}

#03 – Set Up ReactiveFormsModule in Angular 9

To use Reactive forms in Angular app, we need to import ReactiveFormsModule in app.module.ts file.

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule
  ],
})

export class AppModule { }

#04 – Understand Reactive Forms API

To manage the data in Angular 9, we need to understand some core APIs of Reactive forms.

  • FormGroup: FormGroup API holds the values, properties, and validation state of a group in Reactive forms.
  • FormBuilder: It offers convenient methods to control the instances.
  • AbstractControl: This class controls the behavior and properties of, FormGroup, FormControl, and FormArray.
  • FormControl: It is responsible for managing the value and validation status of the specific form control.
  • FormArray: This API manages the values, properties, and validation state of an array.
  • ngSubmit: This event is called when the form is submitted.
<form [formGroup]="myForm" (ngSubmit)="submitForm()" novalidate>
  <mat-form-field class="example-full-width">
    <input matInput placeholder="Name" formControlName="name">
  </mat-form-field>
</form>

#05 – Create Form using Reactive Form and Angular Material 8

We are going to create a form using Angular material 8 UI components. We’ll create a form in Angular 8/9 using FormGroup & FormBuilder Reactive form API. To style Reactive forms we will use Angular material form controls components.

Go to app.component.html file and add the following code.

<mat-sidenav-container>
  <mat-sidenav-content>
    <form [formGroup]="myForm" (ngSubmit)="submitForm()" novalidate>
      
      <!-- Name -->
      <mat-form-field class="example-full-width">
        <input matInput placeholder="Name" formControlName="name">
      </mat-form-field>

      <!-- Email -->
      <mat-form-field class="example-full-width">
        <input matInput placeholder="Email" formControlName="email">
      </mat-form-field>

      <!-- Gender -->
      <div class="misc-bottom-padding">
        <mat-label>Gender:</mat-label>
        <mat-radio-group aria-label="Select an option" formControlName="gender">
          <mat-radio-button value="Male">Male</mat-radio-button>
          <mat-radio-button value="Female">Female</mat-radio-button>
        </mat-radio-group>
      </div>

      <!-- Date picker -->
      <mat-form-field>
        <input matInput readonly [matDatepicker]="picker" placeholder="Date of birth" formControlName="dob"
          (dateChange)="date($event)">
        <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
        <mat-datepicker #picker></mat-datepicker>
      </mat-form-field>

      <!-- Class -->
      <mat-form-field>
        <mat-label>Grade</mat-label>
        <mat-select [(value)]="selected" formControlName="grade">
          <mat-option [value]="gradeArray" *ngFor="let gradeArray of GradeArray">{{gradeArray}}
          </mat-option>
        </mat-select>
      </mat-form-field>

      <!-- Add Subjects -->
      <mat-form-field class="multiple-items">
        <mat-chip-list #chipList>
          <mat-chip *ngFor="let subjectsArray of SubjectsArray" [selectable]="selectable" [removable]="removable"
            (removed)="remove(subjectsArray)">
            {{subjectsArray.name}}
            <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
          </mat-chip>
          <input placeholder="Add subjects" [matChipInputFor]="chipList"
            [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
            (matChipInputTokenEnd)="add($event)">
        </mat-chip-list>
      </mat-form-field>

      <!-- Submit -->
      <div class="button-wrapper">
        <button mat-flat-button color="primary">Submit</button>
      </div>

    </form>
  </mat-sidenav-content>
</mat-sidenav-container>

Go to app.component.ts file and add the following code.

import { Component, ViewChild } from '@angular/core';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
import { FormGroup, FormBuilder } from "@angular/forms";

export interface Subject {
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  visible = true;
  selectable = true;
  removable = true;
  addOnBlur = true;
  myForm: FormGroup;
  @ViewChild('chipList', { static: true }) chipList;
  GradeArray: any = ['8th Grade', '9th Grade', '10th Grade', '11th Grade', '12th Grade'];
  SubjectsArray: Subject[] = [];
  readonly separatorKeysCodes: number[] = [ENTER, COMMA];

  constructor(public fb: FormBuilder) {}

  ngOnInit(): void {
    this.reactiveForm()
  }

  /* Reactive form */
  reactiveForm() {
    this.myForm = this.fb.group({
      name: [''],
      email: [''],
      gender: ['Male'],
      dob: [''],      
      grade: [''],
      subjects: [this.SubjectsArray]
    })
  }

  /* Date */
    date(e) {
      var convertDate = new Date(e.target.value).toISOString().substring(0, 10);
      this.myForm.get('dob').setValue(convertDate, {
        onlyself: true
      })
    }

      /* Add dynamic languages */
  add(event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;
    // Add language
    if ((value || '').trim() && this.SubjectsArray.length < 5) {
      this.SubjectsArray.push({ name: value.trim() })
    }
    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  /* Remove dynamic languages */
  remove(subject: Subject): void {
    const index = this.SubjectsArray.indexOf(subject);
    if (index >= 0) {
      this.SubjectsArray.splice(index, 1);
    }
  }  

  submitForm() {
    console.log(this.myForm.value)
  }

}

#06 – Setup Angular 8/9 Project for Reactive Forms Demo

In next step, we will learn how to validate Reactive forms using Angular material 8. I’ll create a separate function which will handle the errors emitted by reactive forms.

Go to your app.component.ts file and add the following function to handle errors.

import { FormGroup, FormBuilder, Validators } from "@angular/forms";

/* Reactive form */
reactiveForm() {
    this.myForm = this.fb.group({
      name: ['', [Validators.required]],
      email: ['', [Validators.required]],
      gender: ['Male'],
      dob: ['', [Validators.required]],
      grade: [''],
      subjects: [this.SubjectsArray]
    })
}

Go to your app.component.html file and add the angular material form control errors something like this.

<form [formGroup]="myForm" (ngSubmit)="submitForm()" novalidate>
  <mat-form-field>
   <input matInput placeholder="Name" formControlName="name">
   <!-- error -->
   <mat-error *ngIf="errorHandling('name', 'required')">
      You must provide a<strong>name</strong>
   </mat-error>
</mat-form-field>

#07 – Radio Buttons with Reactive Forms.

In this part of the tutorial, I’ll show you how to manage the data of Radio buttons in reactive forms. We’ll create radio buttons with the help of Angular material and also tell you how to set the selected value of radio buttons.

Go to app.component.html file and add the following code.

<mat-radio-group aria-label="Select an option" formControlName="gender">
   <mat-radio-button value="Male">Male</mat-radio-button>
   <mat-radio-button value="Female">Female</mat-radio-button>
</mat-radio-group>

Go to app.component.ts file and add the following code.

reactiveForm() {
  this.myForm = this.fb.group({
    gender: ['Male']
  })
}

#8 – Select Dropdown with Reactive Forms?

We’ll look at how to work with select dropdown in Angular 8/9 in this part of the tutorial. We’ll create select dropdown using angular material forms component. To dynamically manage the select dropdown value, We’ll take help of reactive forms.

Go to app.component.html file and add the following code.

<mat-select [(value)]="selected" formControlName="grade">
   <mat-option [value]="gradeArray" *ngFor="let gradeArray of GradeArray">{{gradeArray}}
   </mat-option>
</mat-select>

Go to app.component.ts file and add the following code.

export class AppComponent {
  GradeArray: any = ['8th Grade', '9th Grade', '10th Grade', '11th Grade', '12th Grade'];

  constructor(public fb: FormBuilder) {}

  ngOnInit(): void {
    this.reactiveForm()
  }

  /* Reactive form */
  reactiveForm() {
    this.myForm = this.fb.group({
      grade: ['']
    })
  }

}

#09 – Working with Angular Material Date-picker using Reactive Forms

Here we’ll learn to work with dates in Angular 8/9. We’ll cover the following topics:

  • Set Angular material datepicker in Angular app.
  • Get Angular material datepicker value using (dateChange)="date($event)" in event.
  • Convert date object to string value

Go app.component.html file and include the given below code.

<!-- Date picker -->
<mat-form-field>
   <input matInput readonly [matDatepicker]="picker" placeholder="Date of birth" formControlName="dob"
   (dateChange)="date($event)">
   <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
   <mat-datepicker #picker></mat-datepicker>
</mat-form-field>

Go app.component.ts file and include the given below code.

export class AppComponent {
 
  constructor(public fb: FormBuilder) {}

  ngOnInit(): void {
    this.reactiveForm()
  }

  /* Reactive form */
  reactiveForm() {
    this.myForm = this.fb.group({
      dob: ['']
    })
  }

  /* Conver date object to string */
    date(e) {
      var convertDate = new Date(e.target.value).toISOString().substring(0, 10);
      this.myForm.get('dob').setValue(convertDate, {
        onlyself: true
      })
    }

}

#10 – Set Multiple Form Values Dynamically in Angular 8/9 and Angular Material Input Chips

In final step, We’ll learn to create multiple form values in a single form field and save them in an array using Angular material input chips and Angular material reactive forms.

Head over to app.component.html file and add the given below code.

<!-- Add Subjects -->
<mat-form-field class="multiple-items">
   <mat-chip-list #chipList>
      <mat-chip *ngFor="let subjectsArray of SubjectsArray" [selectable]="selectable" [removable]="removable"
      (removed)="remove(subjectsArray)">
      {{subjectsArray.name}}
      <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
      </mat-chip>
      <input placeholder="Add subjects" [matChipInputFor]="chipList"
      [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
      (matChipInputTokenEnd)="add($event)">
   </mat-chip-list>
</mat-form-field>

Head over to app.component.ts file and add the given below code.

import { Component, ViewChild } from '@angular/core';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
import { FormGroup, FormBuilder, Validators } from "@angular/forms";

export interface Subject {
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  visible = true;
  selectable = true;
  removable = true;
  addOnBlur = true;
  myForm: FormGroup;
  @ViewChild('chipList', { static: true }) chipList;
  GradeArray: any = ['8th Grade', '9th Grade', '10th Grade', '11th Grade', '12th Grade'];
  SubjectsArray: Subject[] = [];
  readonly separatorKeysCodes: number[] = [ENTER, COMMA];

  constructor(public fb: FormBuilder) {}

  ngOnInit(): void {
    this.reactiveForm()
  }

  /* Reactive form */
  reactiveForm() {
    this.myForm = this.fb.group({
      name: ['', [Validators.required]],
      email: ['', [Validators.required]],
      gender: ['Male'],
      dob: ['', [Validators.required]],
      grade: [''],
      subjects: [this.SubjectsArray]
    })
  }

  /* Date */
    date(e) {
      var convertDate = new Date(e.target.value).toISOString().substring(0, 10);
      this.myForm.get('dob').setValue(convertDate, {
        onlyself: true
      })
    }

      /* Add dynamic languages */
  add(event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;
    // Add language
    if ((value || '').trim() && this.SubjectsArray.length < 5) {
      this.SubjectsArray.push({ name: value.trim() })
    }
    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  /* Remove dynamic languages */
  remove(subject: Subject): void {
    const index = this.SubjectsArray.indexOf(subject);
    if (index >= 0) {
      this.SubjectsArray.splice(index, 1);
    }
  }  

  /* Handle form errors in Angular 8 */
  public errorHandling = (control: string, error: string) => {
    return this.myForm.controls[control].hasError(error);
  }

  submitForm() {
    console.log(this.myForm.value)
  }

}

Finally, we’ve completed Angular 8/9 Reactive Forms Validation with Angular Material 8 tutorial. I hope this tutorial will help you out, please check out the GitHub repo if you find any difficulty in this tutorial.

Digamber Rawat
Digamber Rawat

Full stack developer with a passion for UI/UX design. I create beautiful and useful digital products to solve people’s problem and make their life easy.

Thanks for checking this tutorial out :) Let me know if you have any suggestions or issue related to this tutorial, or you want to request a new tutorial. Just shoot me a mail here.