Custom angular form component
Tags: angular, typescript, controlvalueaccessor, javascript
Published: 2021-08-14 14:16:41

{% github anirbmuk/CustomFormElement no-readme %}

Most of our application requirements are fulfilled using standard HTML elements. However, we may sometimes need to stretch ourselves when we are working for large enterprise applications. In such cases, reusability becomes a strong factor which determines ease of development. Today's use case is one such custom requirement.

This article speaks about creating an Angular component which acts as a lookup - an input field with a search button. The button opens up a modal window, which shows a list of values from which the user may select one. _**Additionally, this new component should also angular-form-ready, which means, it should be capable enough to be registered as a template-driven or reactive form element.**_

![Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqb24o0f46zr7tyxhazd.gif)

Let's first talk about the component itself.

![The GUI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94nuovcejg5ev73ylg6c.JPG)

![app.component.html](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq3wqcch45ads6947e9f.JPG)

The _**app-lookup**_ component takes in a couple of inputs - formConfig and lookupConfig. A sample implementation is shown below:

![Implementation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqac7je3wejppbog16jv.JPG)

When user clicks on the search button, a modal window opens with data fetched from server (in my case a simple promise). Use selects a record and clicks select. The data gets populated on the input form.

![Modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8s0z1mgryy9wbouxy3h.JPG)

![Submitted form 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69rxfnyy3y5uvydn7vhi.JPG)

If _**allowUnlistedValue**_ is set as true, the user will be able to enter a value which does not exist in the list, and the value will be accepted. If not, then the form element will return empty value.

So this is all about describing the component.

---

### Now let's see how to set it up

We need to extend this component so that Angular recognizes this as a valid form element. Since this element is of input type, I have implemented the interface **`ControlValueAccessor`**. This interface needs to implement 3 methods - `writeValue`, `registerOnChange` and `registerOnTouched`.
The `writeValue` method is the one which is responsible to writing your value to the view from your model.
`registerOnChange` is used to propagate changes from your model to the view. This is how the form knows that one of its members has changed its value.
`registerOnTouched` is used to let the wrapper form element know that one of its elements has been marked as touched.


### Error handling

`Question`: Now that we are done with setting up the value read/write operations, how about error handling? How do we let the wrapping angular form know if our custom component has an error and needs to be marked as invalid?
`Answer`: To do this, we inject an instance of `NgControl` into the component, which gives us the `FormControl` instance. It is this form-control object which sets the errors in the component conditionally. Remember, it is a custom component, so everything needs to be set by us :-)
`Note`: The `ErrorStateMatcher` has nothing to do with this implementation, but it is more for the material input component. `ErrorStateMatcher` marks the component in red when it has an error.

![NgControl](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1x824oo1b1g60vnw3pmp.JPG)
![Error handling](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7qoxn4oa60almg0mx0b.JPG)

As a result, if _**allowUnlistedValue**_ is set as false, the user will not be able to enter a value which does not exist in the list, and the component (and subsequently the form) will be marked as invalid. This is demonstrated by disabling the Submit button when form is invalid!

![Submitted form 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2j3u605hq6my6fz78vm.JPG)

---

Do note: A much more in-depth set of instructions for creating custom form elements can be found in a blog by [Pascal Precht](https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html).

And there you go. You have your own angular component ready to be used in a form! You can download the source code from [GitHub](https://github.com/anirbmuk/CustomFormElement) and play around with the configurations.

Cheers!
[Anirban Mukherjee](https://anirbmuk.appspot.com/en)