I am trying to do validation using the
and
. This works fine when user tabs out of the input without filling. B
the easiest way is call markUserNameTouched() method as below on button click on template. We use markAsTouched() on formControl.
public staffLoginForm: FormGroup;
ngOnInit(){
this.staffLoginForm = new FormGroup({
username: new FormControl(null),
password: new FormControl(null)});
markUserNameTouched():void{
this.staffLoginForm.get('username').markAsTouched();
}
If you wish to override this behavior (e.g. to show the error as soon as the invalid control is dirty or when a parent form group is invalid), you can use the errorStateMatcher property of the matInput. The property takes an instance of an ErrorStateMatcher object. An ErrorStateMatcher must implement a single method isErrorState which takes the FormControl for this matInput as well as the parent form and returns a boolean indicating whether errors should be shown. (true indicating that they should be shown, and false indicating that they should not.)
I would make a separate file such as default.error-matcher.ts
/** Error when invalid control is dirty or touched*/
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
return !!(control && control.invalid && (control.dirty || control.touched));
}
}
Then in the TS file add:
matcher = new MyErrorStateMatcher();
Then change the input to use matcher:
<mat-form-field>
<input matInput placeholder="Due Date" name="dueDate" [(ngModel)]="dueDate" [formControl]="dueDateValidator" [errorStateMatcher]="matcher" required>
<mat-error *ngIf="dueDateValidator.invalid">Due Date is required for Tasks</mat-error>
</mat-form-field>
Based on Kyle Pfromer's post, I found my solution (to the same problem):
In the TS file I added the StateMatcher after I found an invalid form, eg.
if (this.myFormGroup.invalid) {
this.matcher = new MyErrorStateMatcher();
return;
}
In the MyErrorStateMatcher class I changed as following:
return !!(control && control.invalid);
I find it confusing that Angular Material is not detecting the error anyway.
Either you can do as "Kyle Pfromer" suggested or as you are using form group, you can mark element as touched on submit with
onSubmit(){ this.formName.get('formControlName').markAsTouched(); }
This works for me. :) On button's click:
this.nameControl.markAsTouched();
GLOBALLY: Show mat-error while typing or touched: Unlike the provided solution, this method will take care of all mat-errors in the app without applying the matcher to each input.
1- Create touched-error-state.matcher.ts file:
import {FormControl, FormGroupDirective, NgForm } from '@angular/forms';
import {ErrorStateMatcher} from '@angular/material/core';
export class TouchedErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
return !!(control && control.invalid && (control.dirty || control.touched));
}
}
2- In app.module import:
import { ErrorStateMatcher } from '@angular/material/core';
import { TouchedErrorStateMatcher } from './your-folder-path/touched-error-state.matcher';
3- Now provide it into the providers:
@NgModule({
providers: [
AuthService,
UserService,
{ provide: ErrorStateMatcher, useClass: TouchedErrorStateMatcher }
],
})
4- Re-Serve the app.