Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display Angular Material mat-error in wrapper

How can I properly display <mat-error> in a container without breaking the layout?

The background is this: I use a lot of basic validators in my template driven forms (required, minlength, pattern) and want to display the corresponding error message.mat-form-fieldonly supports the display of onemat-error` at a time, and for every message I need to display a human readable error message. So every input will look something like this:

<mat-form-field>
  <input matInput required minlength="4" pattern="…">
  <mat-error *ngIf="field?.errors?.required">Field is required</mat-error>
  <mat-error *ngIf="field?.errors?.minlength">Must be at least {{ field!.errors!.minlength.requiredLength }} characters</mat-error>
  <mat-error *ngIf="field?.errors?.pattern">Does not match pattern {{ … }}</mat-error>
</mat-form-field>

I have to do this for every field. Seems pretty redundant!

I have tried several approaches for extracting this pattern from the template:

  • Component
  • *ngFor
  • <ng-container>
  • <ng-template>

However, they all mess up the layout, the error is then sort of displayed within the input field. I assume the issue is that mat-error needs to be a direct descendant of mat-form-field and all my approaches add an extra element between mat-error and mat-form-field.

So how can I handle errors without having to write all the mat-error lines for every input?

like image 819
Georg M. Sorst Avatar asked Nov 05 '18 16:11

Georg M. Sorst


2 Answers

I see that you are using the template driven approach, I tend to go for the Reactive one for any forms that don't class as really simple.

The method used should be made generic, passing in the field. I have used a single use-case for clarity

Typescript class:

get email() {
   return this.form.get('email');
}

 getEmailError() {
    return this.email.hasError('required') ? 'You must enter an email address' :
    this.email.hasError('email') ? 'Not a valid email' : '';
}

Template file:

<mat-form-field>
  <input
    type="email"
    matInput
    placeholder="Your Email"
    autocomplete="false"
    formControlName="email">
  <mat-hint>Please enter an email address</mat-hint>
  <mat-error *ngIf="email.invalid">{{getEmailError()}}</mat-error>
</mat-form-field>
like image 158
Mark Bell Avatar answered Sep 28 '22 00:09

Mark Bell


<mat-form-field>
  <input matInput required minlength="4" pattern="…">

<mat-error *ngfor="let type of (validationTypes$ | async)">
  <mat-error *ngIf="field?.errors[type]">{{validationMessagesService.getValidatorErrorMessage(type, maxLength, 'fieldName')}}</mat-error>
</mat-error>
</mat-form-field>
like image 37
di22 Avatar answered Sep 28 '22 02:09

di22