Do you know you can create your own custom form control elements in Angular ? The thing is it’s actually so easy to do it. All you need is just implement an interface then you are ready to go.
Another thing that I like most about the Angular, It has very clever solutions for our daily basis problems. It breaks down everything for us with few easy implementation then its all fine. I believe it is really something magical. Like the way how it can treat every components as form control just implementing ControlValueAccessor interface. Which defines a set of methods that allow a form control to be connected to a native form control element in the DOM, and includes methods for handling changes to the control’s value as well as validation. Components that implement this interface are known as value accessors, and they are used to create custom form controls in Angular.
We already saw and used this components while working with 3.rd libraries. Some of us even ask the following question!
Yes it is possible and actually quite easy. There are even ready to use implementation that provided by the Angular itself. Just check it out here
Lets start with the ControlValueAccessor
and take a look what is inside in it.
There are 3 methods that you must implement to make it work your custom form component. Lets explain one by one.
1. WriteValue
Since our component will be bound into a form tree, it will be receive value from parent components. In order to transfer this values to our input element we must need to implement writeValue method. There are several ways to do it. First you still rely Angular form elements inside your component. But that make your component to strictly attached to the one of the form module Angular supports.
Instead of relying form modules, we can directly access the DOM and manipulate the element. It might sounds like a bad idea. Since we are creating a shared component that can be used anywhere in the application. It is better to keep independent. But of course we’ll do it with the right way
Using the renderer service provided by Angular, we can directly manipulate the DOM and update the value inside of the Angular ecosystem.
2. RegisterOnChange
When you developing a form component, Angular needs to know when your input has changed. In order to do that it follows something similar we do in react. It passes a callback to our component to listen our changes.
You may ask what happen next ? But keep calm I’ll demonstrate how the magic at the end but first we need to setup everything. So lets continue to next step.
3. RegisterOnTouched
Like we did in the previous step, we will register another callback to notify our parent form element when user interact with the control. So some validation checks can be performed.
4. SetDisabledState
This step is not required. But I am sure you want to disable your form element when the parent form disabled. So it’s better to implement.
Now we can derive disability from upper form elements.
Final Step: Let The Magic Happen
Final Step 1. Bind The Component To The Angular Forms API
We implement the ControlValueAccessor but it is not done yet. We still need to tell the Angular that from now on you can treat our component as a form control value accessor. In order to do that we will provide NG_VALUE_ACCESSOR
token in our components providers. Never heard of before ? Let me break down for you.
It is a token used in Angular to mark a class as a provider of form control value accessor. This token is used to create a bridge between the Angular forms API and the native form control. It is used in custom form controls to enable two-way data binding between the form control and the Angular form.
Final Step 2. Emit Events
Now we will emit our form events such as change and focus events. Then we will be able to notify upper forms bound to the our custom form element. This is the also very easy to implement. We just need to trigger changed and touched events.
Fellas if you manage to come to the this step I congrats you. It’s done 🙂 Our component is now ready to pretend as a value accessor. From now on you can use it like a form element.
If you encounter any error in the process. I shared a fully working example in the stackblitz. You can review if you like. If still not works let me know. I would like to help as much as I can 🙂
Wanna know more about the Angular ? Here are some useful links you can take a look at.
Do you want to know how you can use Interceptors effectively ? Checked out here