Angular Material - show mat-error on button click

2020-05-30 03:50发布

问题:

I am trying to do validation using the <mat-for-field> and <mat-error>. This works fine when user tabs out of the input without filling. But how do I force this error to show when I click a button? I am not using submit. Also, using template-driven forms.

This is my code:

HTML:

<mat-form-field>
    <input matInput placeholder="Due Date" name="dueDate" [(ngModel)]="dueDate" [formControl]="dueDateValidator" required>
    <mat-error *ngIf="dueDateValidator.invalid">Due Date is required for Tasks</mat-error>
</mat-form-field>

TS:

dueDateValidator: FormControl = new FormControl('', [Validators.required]);

回答1:

See how to use a form with a custom ErrorStateMatcher

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>


回答2:

Since you want to show mat error on button's click, please try the below: For Angular6 version:

1). import below:
    import { FormControl, FormBuilder, FormGroup } from '@angular/forms';

2). declare form control in .ts file:
    nameControl = new FormControl('');

3). put control in html:
    <mat-form-field  style="width: 100%" floatPlaceholder="never">
      <input matInput placeholder="your placeholder text" [formControl]="nameControl" 
        required/>
      <mat-error *ngIf="nameControl.errors?.required">name is required</mat-error>
    </mat-form-field>

3). on button's click:
    this.nameControl.markAsTouched();

It's important to check how you are using the form control, ".markAsTouched()" on point 3 will show the mat error for the corresponding form control.



回答3:

This works for me. :) On button's click:

this.nameControl.markAsTouched();


回答4:

Angular 8 has a new forms method: markAllAsTouched();

This will mark a control/form and ALL DESCENDANTS as touched!!!

So:

this.form.markAllAsTouched();

Is the solution.



回答5:

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.



回答6:

I am providing 3 different solutions for different scenarios, use the one which suits you.

  • If you are using a form, then do

    this.form.markAllAsTouched();
    
  • If you need a particular field to be affected inside form, then filter that nameControl and do

    nameControl.markAsTouched();
    
  • If you are not using forms, then specify a ref for the input element and initialize variable in ts file & do as follows,

    @ViewChild('myInputRef') myInputRef; // Initialize the ref of input element
    .
    .
    this.myInputRef.control.markAsTouched()
    


回答7:

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


回答8:

You can also easily call the AbstractControl.updateValueAndValidity() function on button click. This will run the validation process on the corresponding ForControl again and show errors, if there are some (based on your Validators).

So, in your example:

    checkForErrorsOnButtonClick(): void {
      dueDateValidator.updateValueAndValidity();
    }


回答9:

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