1

I try to display an error message and error icon when matInput has an error (controlled by a formControl). But if the form is submited without touch the field, error is not displayed.

View code playground on stackblitz

Or here is my code:

app.component.ts

ngOnInit() {
    this.formGroup = new FormGroup({
      email: new FormControl(null, [Validators.required, Validators.email]),
    });
}
get emailHasError() {
    return (
      !this.formGroup.get('email').valid && this.formGroup.get('email').touched
    );
}

app.component.html

<form [formGroup]="formGroup" class="form">
  <mat-form-field class="form-element">
    <input matInput placeholder="Email address" formControlName="email" />
    <mat-error *ngIf="emailHasError">
      {{ errorEmail }}
    </mat-error>
  </mat-form-field>
  <div class="form-element">
    <button mat-raised-button color="primary" type="submit" class="button">
      Submit Form
    </button>
  </div>
</form>

However, the matInput field turns red and seems to receive the error.

I read some solution that suggests to toggle a property isSubmit on form submit. But seems to be ugly and and this requires passing this property to the child component if the form is split into several components.

How does Angular Material manage to detect if the form is submitted in order to display the error?

EDIT:

The only solution I found for now is to check classList with @ViewChild as follow. But it still seems to be a hacky way... On stackblitz I process as follow:

@ViewChild('matInput') matInput: ElementRef;
get hasError() {
    return this.matInput?.nativeElement?.classList?.contains('ng-invalid');
}
<input
  matInput
  #matInput
  placeholder="Email address"
  formControlName="email"
/>
2
  • 1
    Have you looked at creating a custom errorStateMatcher? Commented Apr 10, 2022 at 8:30
  • Yes I looked but I don't find a solution to completly solve my issue with it. Maybe I'm doing something wrong. Commented Apr 11, 2022 at 6:17

2 Answers 2

1

No need to return emailHasError() and errorEmail(), and checking touched inside component, angular material input field automatically checks that and shows mat-error only if a field is touched.

Instead directly check errors in html and show the message accordingly.

See working demo here

Added this css in styles.css to show only first error if there are more than one -

/* shows only first error */
.mat-error:not(:first-of-type) {
  display: none !important;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Ok but I still not able to know in my component if the error is shown or not. Suppose I want to display an error icon as suffix when an error is show. Any idea how to handle that: stackblitz.com/edit/formcontrol-angular-error-icon
@ZecKa in that case, use markAsTouched() method on formControl, see the demo here - stackblitz.com/edit/…
My goal is to create a wrapper for matInput. So using markAsTouched every time a form is submitted doesn't seem viable. I want to get error state info from matInput. The only solution I found is to check classList with viewChild as follow: stackblitz.com/edit/… ---> But it's seems hacky way...
1

A custom ErrorStateMatcher may be a neat solution for this problem.

  1. Create a custom ErrorStateMatcher like so:
class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(
    control: FormControl | null,
    form: FormGroupDirective | NgForm | null
  ): boolean {
    const isSubmitted = form && form.submitted;
    return !!(
      control &&
      control.invalid &&
      (control.dirty || control.touched || isSubmitted)
    );
  }
}
  1. Add it to your component class
  matcher = new MyErrorStateMatcher();
  1. Use it in your template
  <mat-form-field class="form-element">
    <input
      matInput
      placeholder="Email address"
      formControlName="email"
      [errorStateMatcher]="matcher"
    />
    <mat-error *ngIf="formGroup.invalid">
      <mat-icon mat-suffix color="warn">error</mat-icon>
      {{ errorEmail }}
    </mat-error>
  </mat-form-field>

The ErrorStateMatcher controls exactly which set of conditions should display an error response in the UI. In the current example, it will display whenever isSubmitted is true, even if the form control is not "dirty" or "touched".

Here's a stackblitz demo.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.