Handle form errors using components Angular - TypeScript

L Y E S  -  C H I O U K H picture L Y E S - C H I O U K H · Apr 10, 2018 · Viewed 30.5k times · Source

I am currently working on a form in Angular/Typescript of several fields (more than 10 fields), and I wanted to manage the errors more properly without duplicating code in my html page.

Here is an example of a form :

In my case, I have two types of validation for my form :

  • Html validation : required, maxSize, ... etc.
  • Back validation : For example, invalid account, size of loaded file, ... etc.

I try to using a directive as mentioned here

<form [formGroup]="myForm">
     <label>Name</label>
     <input type="text" formControlName="name">
     <div invalidmessage="name">
        <p *invalidType="'required'">Please provide name</p>
     </div>
     <label>Lastname</label>
     <input type="text" formControlName="lastname">
     <div invalidmessage="lastname">
        <p *invalidType="'required'">Please provide lastname</p>
     </div>
     <label>Email</label>
     <input type="text" formControlName="email">
     <div invalidmessage="email">
        <p *invalidType="'required'">Please provide email</p>
        <p *invalidType="'email'">Please provide valid email</p>
     </div>
</form>

But even with this solution the code is always duplicated and no ability to handle both types of validation.

Do you have another approach ? Is use components appropriate in this case ? If yes, how can do it.

Thank you in advance for your investment.

Answer

JayChase picture JayChase · May 9, 2018

You can move the validation errors into a component and pass in the formControl.errors as an input property. That way all the validation messages can be re-used. Here is an example on StackBlitz. The code is using Angular Material but still should be handy even if you aren't.

validation-errors.component.ts

import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup, ValidationErrors } from '@angular/forms';

@Component({
  selector: 'validation-errors',
  templateUrl: './validation-errors.component.html',
  styleUrls: ['./validation-errors.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ValidationErrorsComponent implements OnInit {
  @Input() errors: ValidationErrors;

  constructor() {}

  ngOnInit() {}

}

validation-errors.component.html

<ng-container *ngIf="errors && errors['required']"> Required</ng-container>
<ng-container *ngIf="errors && errors['notUnique']">Already exists</ng-container>
<ng-container *ngIf="errors && errors['email']">Please enter a valid email</ng-container>

For the back validation messages set the error manually on the form control.

const nameControl = this.userForm.get('name');
nameControl.setErrors({
  "notUnique": true
});

To use the validation component on the form:

   <form [formGroup]="userForm" (ngSubmit)="submit()">
      <mat-form-field>
        <input matInput placeholder="name" formControlName="name" required>
        <mat-error *ngIf="userForm.get('name').status === 'INVALID'">
          <validation-errors [errors]="userForm.get('name').errors"></validation-errors>      
        </mat-error>
      </mat-form-field>
      <mat-form-field>
        <input matInput placeholder="email" formControlName="email" required>
        <mat-error *ngIf="userForm.get('email').status === 'INVALID'">
          <validation-errors [errors]="userForm.get('email').errors"></validation-errors>
        </mat-error>
      </mat-form-field>
      <button mat-raised-button class="mat-raised-button" color="accent">SUBMIT</button>
    </form>