Search code examples
angulartypescript

Form validation for required fields on Submit in Angular 17


I have many fields like firstName, lastName, etc which is made required from the backend. If I submit the form without filling up the firstName, it throws the following error in the Network Preview. If I fill up firstName and leave lastName empty, it will throw another error: lastName is required in the Network Preview:

{
    "status": "failed",
    "error": {
        "message": "Invalid request data. Please review the request and try again.",
        "code": [
            {
                "message": "firstName is required",
                "code": "any.required"
            }
        ]
    }
}

HTML:

<input type="text" class="form-control" [(ngModel)]="registration.firstName">
<input type="text" class="form-control" [(ngModel)]="registration.lastName">
<button type="button" class="btn btn-success" (click)="createRegistration(registration)">Submit</button>

I simply want to throw the error message as shown in the Network Preview when someone try to click Submit button somewhere on the page:

<p>firstName is required</p>

TS:

createRegistration(registration:StudentRegistration){
    this.coreService.addRegistration(registration).subscribe({
      next: (res: any) => {
        this.registration = res.data || {} as StudentRegistration;
        this.opd.registration = res.data._id;
        this.createOpdStudent()
      },
      error: (err) => {
        console.log(err);
      }
    })
  }

I have seen a lot of frontend-validation tutorials in Angular but that's just too much effort as I have to validate every field again in the frontend. I can't find any backend validation tutorial like in my case.

PS: Working frontend method I don't want to use as there are multiple forms with 100s of fields

<p *ngIf="registration.firstName == '' || registration.firstName == undefined">First name is compulsory</p>

Solution

  • In the error callback, you can extract the error message as below:

    errorMessages: string[] = [];
    
    error: (err) => {
      console.log(err);
    
      let errorResponse = err.error;
      this.errorMessages = errorResponse.code.map((x: any) => x.message);
    }
    

    To display set of errorMessages:

    <div *ngFor="let errorMessage of errorMessages">
      {{ errorMessage }}
    </div>
    

    If you are looking to display the error messages by section field, you should need the implementation to check and get the error message by field name:

    <div [ngClass]="{'show': hasError('firstName'), 'hide': !hasError('firstName')}">
      <span>FirstName error</span>
      <div *ngFor="let errorMessage of getErrorsByField('firstName')">
        {{ errorMessage }}
      </div>
    </div>
    
    hasError(fieldName: string) {
      return this.errorMessages.some((x) => x.indexOf(fieldName) > -1);
    }
    
    getErrorsByField(fieldName: string) {
      return this.errorMessages.filter((x) => x.indexOf(fieldName) > -1);
    }
    

    Demo @ StackBlitz