Show Validation Error Messages for Reactive Forms in Angular 9

by Steven McLintock

Angular logo

In Angular there are two different types of forms for a user to input data: reactive and template-driven. I personally prefer using reactive forms as they seem to follow the separation of concerns principle, where the core functionality is in the component and the presentation layer is stored in the template.

We can define a reactive form within a component and check if the form is valid, but if there’s an error, how do we indicate this to the user in a manner they can understand and rectify accordingly?

In this example, I’ll define a reactive form with one text field. We’ll configure this field to have a few validation rules before the user can submit the form. These will be to set the field as required, it’s value to be of a minimum character length of 3 and have a maximum character length of 30.

The reactive form defined in the component:

this.formGroup = this.formBuilder.group({
    toDo: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(30)]]
});

Show the Field is Required Using the Label

Using data binding in Angular, we can dynamically change the label to indicate the field is required. This will at least let the user know that the field is not optional:

Label for required field for reactive form in Angular
<label for="toDo">
    Add New To Do
    <span 
        class="text-danger" 
        *ngIf="formGroup.get('toDo').errors && 
            formGroup.get('toDo').hasError('required')"
    >*</span>
</label>

Show the Validation State Using the Field

We can also use data binding to apply the classes ‘valid’ or ‘invalid’ to the field to indicate if there is a validation error (or if the field is valid):

Valid field in reactive form in Angular
<input 
    id="toDo" 
    type="text" 
    class="form-control" 
    placeholder="What is it you want to do?"
    formControlName="toDo"
    [class.valid]="formGroup.get('toDo').valid && 
        (formGroup.get('toDo').dirty || formGroup.get('toDo').touched)"
    [class.invalid]="formGroup.get('toDo').invalid && 
        (formGroup.get('toDo').dirty || formGroup.get('toDo').touched)" />

Show Each of the Validation Error Messages

We’ll need to clearly indicate to the user if a field is required, or if the user has not met the validation rules set for a minimum character length or exceeded a maximum character length. You could also add to this to include other validation rules such as email addresses or forbidden names. Let’s show each error message using data binding and HTML:

Required error message:

Required field in reactive form in Angular

Minimum length error message:

Minimum length error in reactive form in Angular

Maximum length error message:

Maximum length error in reactive form in Angular
<div *ngIf="formGroup.get('toDo').invalid && 
        formGroup.get('toDo').errors && 
        (formGroup.get('toDo').dirty || formGroup.get('toDo').touched)">
    <small class="text-danger"
        *ngIf="formGroup.get('toDo').hasError('required')">
        This field is required.
    </small>
    <small class="text-danger"
        *ngIf="formGroup.get('toDo').hasError('minlength')">
        The minimum length for this field is {{formGroup.get('toDo').errors.minlength.requiredLength}} characters.
    </small>
    <small class="text-danger"
        *ngIf="formGroup.get('toDo').hasError('maxlength')">
        The maximum length for this field is {{formGroup.get('toDo').errors.maxlength.requiredLength}} characters.
    </small>
</div>

Disable the Submit Button

Finally, we can disable the submit button if the form is invalid:

<button class="btn btn-primary" [disabled]="formGroup.invalid">Add To Do</button>

Instead of duplicating this code for each field and for all forms, a better approach might be to abstract this into a separate component that can be reused across the codebase. However, this should hopefully be a good example of how to show validation error messages to the user in a reactive form.

Steven McLintock

Kilt & Code is a blog written by Steven McLintock, a full-stack developer originally from Scotland. Steven primarily uses Microsoft's .NET framework in addition to Angular and has been working as a developer since 2006.