Angular Material Custom ErrorStateMatcher

By Arvind Rai, October 23, 2022
On this page we will learn to create custom ErrorStateMatcher and use it in our Angular Material application.
1. The ErrorStateMatcher is a provider that defines how form controls behave with regards to displaying error messages.
2. The ErrorStateMatcher contains a method isErrorState() that returns Boolean value. If return value is true, error message will be shown on UI otherwise no error message will be shown.
3. Find the declaration of ErrorStateMatcher.isErrorState() method from Angular doc.
isErrorState(control: AbstractControl | null, form: FormGroupDirective | NgForm | null): boolean; 
4. To create custom ErrorStateMatcher, create a class implementing ErrorStateMatcher and defining its isErrorState() method.
5. We can use our custom ErrorStateMatcher either locally or globally. For local use, the <input> element provides errorStateMatcher attribute that is assigned with the instance of custom ErrorStateMatcher.
6. To configure ErrorStateMatcher globally, use ErrorStateMatcher provider.

Technologies Used

Find the technologies being used in our example.
1. Angular 13.1.0
2. Angular Material 13.3.9
3. Node.js 12.20.0
4. NPM 8.2.0

Creating Custom ErrorStateMatcher

1. By default the error messages are shown when the control is invalid and either the user has touched the element or the parent form has been submitted.
2. We can change the default behavior by customizing the ErrorStateMatcher.isErrorState() method definition. For this, we need to create a class implementing ErrorStateMatcher and customize isErrorState() method.
export class CustomErrorStateMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null) {
        return (control?.invalid && control.dirty) ?? false;
    }
} 
Now error message will be shown when control is invalid and dirty. Control is considered to be dirty when value of control has been changed.
3. To use custom ErrorStateMatcher locally, create the instance of CustomErrorStateMatcher.
TypeScript code:
esMatcher = new CustomErrorStateMatcher(); 
HTML template code:
Bind esMatcher instance with errorStateMatcher attribute.
<input matInput 
   formControlName="username" 
   [errorStateMatcher]="esMatcher" 
   placeholder="Username"> 
4. Import ErrorStateMatcher as following.
import { ErrorStateMatcher } from '@angular/material/core'; 

Using Custom ErrorStateMatcher Globally

We can use our custom ErrorStateMatcher globally by configuring it in application module.
providers: [
  { provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher }
] 
Now by default every <input> element will use CustomErrorStateMatcher.

Complete Example

Find the custom ErrorStateMatcher.
custom-error-state-matcher.ts
import { ErrorStateMatcher } from '@angular/material/core';
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';

export class CustomErrorStateMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null) {
        return (control?.invalid && control.dirty) ?? false;
    }
} 
In our HTML template, we have two <input> elements, one for username and second for password. The username field is using CustomErrorStateMatcher locally.
reactive-form.component.html
<form [formGroup]="personForm" (ngSubmit)="onFormSubmit()">
  <div>
    <mat-form-field>
      <input matInput formControlName="username" [errorStateMatcher]="esMatcher" placeholder="Username">
      <mat-error *ngIf="username?.hasError('required')">
        Username is required.
      </mat-error>
    </mat-form-field>
  </div>
  <div>
    <mat-form-field>
      <input matInput type="password" formControlName="password" placeholder="Password">
      <mat-error *ngIf="password?.hasError('required')">
        Password is required.
      </mat-error>
    </mat-form-field>
  </div>
  <div>
    <button mat-raised-button>Submit</button>
  </div>
</form> 
reactive-form.component.ts
import { Component } from '@angular/core';
import { Validators, FormBuilder } from '@angular/forms';
import { CustomErrorStateMatcher } from './custom-error-state-matcher';
import { PersonService } from './person.service';

@Component({
  selector: 'app-reactive',
  templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent {
  esMatcher = new CustomErrorStateMatcher();
  constructor(private formBuilder: FormBuilder,
    private personService: PersonService) { }
  personForm = this.formBuilder.group({
    username: ['', Validators.required],
    password: ['', Validators.required],
  });
  onFormSubmit() {
    this.personService.savePerson(this.personForm.value);
  }
  get username() {
    return this.personForm.get('username');
  }
  get password() {
    return this.personForm.get('password');
  }
} 
person.ts
export interface Person {
  username: string;
  password: string;
} 
person.service.ts
import { Injectable } from '@angular/core';
import { Person } from './person';

@Injectable({
  providedIn: 'root'
})
export class PersonService {
  savePerson(person: Person) {
    console.log(person);
  }
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-reactive></app-reactive>
  ` 
})
export class AppComponent {
} 
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { ErrorStateMatcher } from '@angular/material/core';
import { CustomErrorStateMatcher } from './custom-error-state-matcher';
import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './reactive-form.component';

@NgModule({
  declarations: [
    AppComponent,
    ReactiveFormComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule
  ],
  providers: [
    //For Global configuration
    //{ provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Install Angular CLI using link.
2. Install Angular Material using link.
3. Download source code using download link given below on this page.
4. Use downloaded src in your Angular CLI application.
5. Run ng serve using command prompt.
6. Access the URL http://localhost:4200
Find the print screen of the output.
Angular Material Custom ErrorStateMatcher

Reference

Angular Material Input

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI











©2022 concretepage.com | Privacy Policy | Contact Us