Handling Validation Errors
In the last lesson, we discussed validators. Naturally, a failed validator means there is something wrong, and if there is something wrong we are going to need to inform the user what specifically is wrong.
This seems like a good time to tell a little story about a problem my wife just encountered with an online form. Having filled out a large form, it would not submit indicating that there was some error with one of the fields. Only, the form didn’t say which field had the problem. She emailed the company for help, and they emailed her a list of potential validation issues with different fields. This is probably the most absurd example I have heard of, but if something does go wrong, we want to clearly indicate to the user what has gone wrong and where so that they can fix it. We certainly don’t want to be emailing our users the validation requirements for a form.
By default, if one of our validators fails, nothing obvious happens. Let’s say that we prevent our form from being submitted if there are validation errors:
<form [formGroup]="myForm" (ngSubmit)="handleSubmit()">
<div>
<input formControlName="username" type="text" />
<span *ngIf="myForm.controls.username.statusChanges | async as status">
{{ status }}
</span>
</div>
<div>
<input formControlName="age" type="number" />
</div>
<button type="submit" [disabled]="myForm.pending">Submit</button>
</form>
The user will be able to see that the submit button is disabled, but they won’t know why. We could quite easily add a message like this:
<form [formGroup]="myForm" (ngSubmit)="handleSubmit()">
<div>
<input formControlName="username" type="text" />
<span *ngIf="myForm.controls.username.statusChanges | async as status">
{{ status }}
</span>
</div>
<div>
<input formControlName="age" type="number" />
</div>
<p *ngIf="!myForm.valid">There are errors with the form!</p>
<button type="submit" [disabled]="myForm.pending">Submit</button>
</form>
Now the user will know that there was some validation issue with the form that they need to fix, but they still don’t know what specifically the issue was. Dealing with this issue is not trivial, and the larger our form becomes the more difficult it becomes to manage unless we are using some sort of scalable solution.
The Obvious Way
The easiest thing we can do is add an *ngIf
that checks if the field is valid and displays an error if it is not:
<form [formGroup]="myForm" (ngSubmit)="handleSubmit()">
<div>
<input formControlName="username" type="text" />
<span *ngIf="myForm.controls.username.statusChanges | async as status">
{{ status }}
</span>
<p *ngIf="!myForm.controls.username.valid">
Please provide a username that is not taken
</p>
</div>
<div>
<input formControlName="age" type="number" />
<p *ngIf="!myForm.controls.age.valid">Age must be greater than 18</p>
</div>
<div>
<input formControlName="password" type="password" />
<p *ngIf="!myForm.controls.password.valid">
Password must be at least 8 characters long
</p>
</div>
<div>
<input formControlName="confirmPassword" type="password" />
<p *ngIf="myForm.hasError('passwordMatch')">Must match password</p>
</div>
<p *ngIf="!myForm.valid">There are errors with the form!</p>
<button type="submit" [disabled]="myForm.pending">Submit</button>
</form>