This is the third in a series on building forms in Angular using the Reactive Forms technique. I recommend that you read Part 1  and Part 2 before continuing as this post builds upon topics introduced in Parts 1 & 2. In order to illustrate various aspects of Reactive Forms, I have created a small demo application which you can download and run on your machine as you follow along.

In this post I will talk about form validation. In Part I, I briefly touched upon how to specify validations for a form field. Let’s have a look at the code again.

If we take a look at the receivedDate control, we see that we have specified two validations – the built in ‘required’ validation and the custom validation ‘validDate’. The ‘required’ validation is straightforward and will be satisfied if the user enters any value  in the form input element associated with receivedDate. Lets now take a look at our custom validDate ‘validation’. The code for all custom validations in our demo application resides in the file ‘validation-helper.ts’.

A custom validator is a function that takes a FormControl as input and returns null if there are no validation errors or else an object containing the error(s) as key value pairs. The above function uses the popular javascript library moment.js to check whether the user has entered a valid date in the format “DDMM/YYYY”. If the entered date is valid then the function returns null or else an object containing a key ‘validDate’ and value { valid:false} .

Lets now look at how we display validation errors( if any) to the user. In our template we have the following lines.

Right below the input field for received date we have a span tag within which the error is displayed by the showError() method in the component class using interpolation. Lets see what the showError method does.

The showError method takes the name of the form control and checks if the errors property of the FormControl is not null which means that there are validation errors on the control. It then retrieves the error keys from the errors property and passes it along to the getMsg method to retrieve the  error message(s) to display. The showError method is generic and can be applied to any form control. Lets have a look at the span tag again.

What does the ngClass directive do? It allows you to conditionally assign a list of classes to an element. For example , the ‘error’ class will be applied to the span if the shouldShowError method returns true.

Apart from checking if the form control has errors we also check whether the form control has been touched. This means that the ‘error’ class will only be applied when the user has visited the control and has not entered a valid value.

Finally lets look at the validation for the consignment items. Going back to the form requirements discussed in Part I, the user needs to add at least one item to each consignment. The user needs to choose the tea type and enter the number of containers and weight per container, both of which should be numeric fields. In our createForm method where we create the initial form model, we call a function this.addItemListValidations();

In this method, we use the setValidators method on the items FormArray to specify the custom validator ‘validateItemList’. We then subscribe to the valueChanges observable for the items array and update the list of  error messages to be displayed based on the current state of the form controls in the items array. I will not go into the details of the ‘validateItemList’ since it does not introduce any new Angular related concept and if you look at the code its fairly clear what the method does. But lets look again at the last line of the above method. Rather than subscribing to the valueChanges Observable directly, we apply the debounceTime operator to the Observable before subscribing to it. We do this to allow the user to enter values for all the required fields in an item entry before displaying any errors. If we did not do that, the user would be shown error messages asking her to enter no of containers and weight per container as soon as she chose a tea type without allowing her the time to enter these values. The debounceTime operator essentially waits for the specified amount of time( in our case 2000 milliseconds ) and emits the event only if the event has not occurred again within the specified time. So when the user enters the tea type, although a valueChange event occurs, it is not emitted right away. Only if the user does not enter the number of containers or weight per containing within 2 seconds is the  error message shown.

In this article we covered the following :-

  • Writing custom validators in Angular.
  • Writing generic functions to handle the display of error messages.
  • Using the debounceTime reactive operator to allow the user sufficient time to enter valid values before displaying error messages.
Reactive Forms in Angular – A Practical Guide (Part 3)
Tagged on: