I ll take you through a 6 steps progression on custom validations. We ll go from out of the box Angular provided validations to reusable directives components. In this article, we’ll cover out of the box validations and unit testing/creating our first custom validation as a directive.
Step 1 - Out of the box
Lets see a first simple example where we take advantage of out of the box validations.
This is what is going on…
We setup the searchForm so that html5 validation does not kick in. We did so adding the attribute novalidate to the form definition.
We created an input of type text and we marked it as required. This sets required validation error key if the value is not entered.
The input’s label has ngClass so that if the leaving_from.$invalid error key is set, we applied the style ‘error-req’ which makes the label change its color to red.
We created a list of errors above the form and we applied ngShow so this error is only displayed when that error key exists.
At work, we usually hide all error until the user has submitted the form for the first time. We accomplished this by setting an additional flag in our controller (submitted). Angular provides flag to identify the user has interacted with the form (pristine and dirty) but these are not enough when trying to wait till user has submitted the form.
We also add a submit and reset methods in our controller.
Based on the submitted flag we hide all error messages till the user has actually submitted the form.
Lets take a look at the different errors we listed.
- formName.fieldName.$invalid : searchForm.leaving_from.$invalid is looking at the validity of this field. This means all other rules should have passed to clean this error.
- formName.fieldName.$error : is the object containing all references to all invalid rules for an specific field.
- formName.fieldName.$error.required : searchForm.leaving_from.$error.required is looking if our specific field has been entered by the user.
- formName.fieldName.$error.minlength : searchForm.leaving_from.$error.minlength is looking if our specific field has at least 3 characters.
- formName.$error : is the object has containing all references to all invalid rules for all fields inside the form.
Note: Other built-in validations are: email, max, maxlength, min, minlength, number, pattern, required, url. More info: angular-docs
If you would like to see the working example, launch the demo.
Step 2 - Custom Validation
Now we will write a simple custom validation. Custom validations could be written in a controller but if you do so you would end up with a non reusable code block and the now the controller would have more than one reason to change. The best practice and the angularesque way is to write a directive.
I talked to the Business Analyst already and he sent me the new Acceptance Criteria:
|1||I (the user) enter an airport code starting with letter different than ‘A’ or ‘a’||I submit the form||I should see the error message ‘Airport Code should start with letter A’|
Lets start with the directive’s unit test:
The NgModelController has an array of $parsers functions and another array of $formatters functions. The validation can occur in two places: - Model to View update - Whenever the bound model changes, all functions in NgModelController#$formatters array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through NgModelController#$setValidity. - View to Model update - In a similar way, whenever a user interacts with a control it calls NgModelController#$setViewValue. This in turn pipelines all functions in the NgModelController#$parsers array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through NgModelController#$setValidity.
We are going to follow the View to Model update. No need for scope.watch as angular will execute the parsers array of functions every time the user interacts with the control. Here is our directive:
If you would like to play/see with the unit test, launch this demo.
Now that we have a working/tested directive for our custom validation, its time we apply it to our html. The first step is to add it to our input.
And then we add our error message to the errors’ list.
That’s it. If you would like to play/see with the complete example, launch this demo.
On Part 2 we will go through 4 more progressions on custom validations. We will handle much more complex validations over a combination of fields. Stay tuned.