Adding Integrated Validation to Custom Form Controls in Angular
Last week I came across an article that talks about how we (probably) don’t need ReCAPTCHA. Although I have already written a detailed article about how to integrate ReCAPTCHA in Angular, inspired by this article, I decided to create a math Captcha component, that implements a custom validation and share the result with you.
Let’s get started.
Create the Captcha Component
We want our captcha component to integrate with Angular forms, so first, let’s implement the ControlValueAccessor
interface:
We have implemented the three methods that the ControlValueAccessor
requires. In our case, we don’t care about the writeValue()
method, so we leave it empty. If you want to learn more about this topic, check out the following article:
Next, let’s create the component’s template. In order to display the question, we’ll use canvas. This will make sure it will not be present in the DOM, thus avoiding robots from grabbing it.
Now, let’s grab a reference to the canvas element from the component and draw the question:
The createCaptcha()
method is straightforward. It generates two random numbers, and draws them by using the fillText
canvas method. We also save the question’s answer, so that we can validate that against the user’s input.
Let’s see how we can implement the validation part. There are many ways to add custom validation to a form control, but in our case, we want the validation to be baked into in the component.
Using the NG_VALIDATORS Provider
We need to register our component with the NG_VALIDATORS
provider, and implement the validate()
method:
The validate()
method will be called with the FormControl
instance when the control’s value changes. When it’s called, we check the current control value against the question’s answer. If it doesn’t match, we return an error
object, which will mark the current control as invalid.
Now, we’re ready to use our captcha component:
We can export the ngForm
directive to a local variable and use its submitted
property as an indication to whether the form submission has been triggered. If it has been, and the captcha is invalid, we show the error.
Manually Register the Control
The alternative is to obtain a reference to the form control directive via DI, and set the value accessor property manually:
We have a reference to the underlying control, and we register the validator function using the setValidators
method.
Note that when utilizing this option, we can’t register our component with the NG_VALUE_ACCESSOR
provider; If we do so, we’ll have a circular dependency and an error will be thrown.
🚀 Have You Tried Akita Yet?
One of the leading state management libraries, Akita has been used in countless production environments. It is constantly being developed and improved.
Whether it is entities arriving from the server or UI state data, Akita has custom-built stores, powerful tools, and tailor-made plugins, which all help to manage the data and negate the need for massive amounts of boilerplate code. We/I highly recommend that you try it out.
Follow me on Medium or Twitter to read more about Angular, Akita and JS!
You can play with the source code here.