Neistow
Neistow

Reputation: 1244

What is flexible way to show form field errors in angular

So the question is the same as in the title: what is flexible and moreover extensible way to show errors when using angular/angular material.

Every example I saw in angular material docs / angular docs / articles is just using dumb ngIf copypaste like this:

<form class="example-form">
  <mat-form-field class="example-full-width" appearance="fill">
    <mat-label>Email</mat-label>
    <input type="email" matInput [formControl]="emailFormControl"
           placeholder="Ex. [email protected]">
    <mat-error *ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')">
      Please enter a valid email address
    </mat-error>
    <mat-error *ngIf="emailFormControl.hasError('required')">
      Email is <strong>required</strong>
    </mat-error>
  </mat-form-field>
</form>

I came up with the following solution: just create a helper function where I can pass my parent formGroup and get errors, but this doesn't seems work quite well with nested forms and it doesn't allow me to translate messages since I don't have access to DI

Example of my approach:

export function getErrorMessages(formGroup: FormGroup): { [key: string]: string } {
    const errorMessages: { [key: string]: string } = {};
    const controls = formGroup.controls;

    for (const controlName of Object.keys(controls)) {
        const control = controls[controlName];

        if (control.errors?.required) {
            errorMessages[controlName] = 'Field is required';
        } else if (control.errors?.email) {
            errorMessages[controlName] = 'You must provide a valid email';
        }
        // a bunch more branches
    }

    return errorMessages;
}

Component

    public signinForm = this.formBuilder.group({
        email: ['', [Validators.email, Validators.required]],
        password: ['', [Validators.required]]
    });

    public get errors() {
        return getErrorMessages(this.signinForm);
    }

Usage in template

    <mat-form-field appearance="fill">
        <mat-label>{{ 'AUTH.EMAIL' | translate }}</mat-label>
        <input matInput
               formControlName="email"
               [placeholder]="'AUTH.EMAIL_PLACEHOLDER' | translate"
        >
        <mat-error>{{ errors['email'] }}</mat-error>
    </mat-form-field>

EDIT:

Recently I've found an article that shows seamless and quite flexible approach that I've searched for.

Upvotes: 0

Views: 356

Answers (1)

Timothy
Timothy

Reputation: 3593

To simplify your life you can use this extension https://github.com/ngneat/error-tailor

Upvotes: 3

Related Questions