Creating custom HTML Elements with NgRx Forms

Ayush Thakur
5 min readMay 15, 2022

This article will help you create custom form components in Angular that work in sync with NgRx form controls. The most common example can be a star rating component where in the feedback form you can rate by clicking on the stars.

We will consider a simpler example so that we don’t have a lot of HTML and CSS code, since that is not the objective. After finishing this article you can easily extend the functionality in any way you want.

Photo by Kelly Sikkema on Unsplash

prerequisites to better understand this article

  • Understanding of NgRx & NgRx Forms is essential since we wont be covering it in this article. Please go through below links to gain better understanding on above topics.

Example App

We are going to create a custom input component that works with form controls and adds any suffix provided, to the input view.

The form control always stores just the value. Our custom component will handle showing the suffix (in this example a % symbol) when the user is not actively typing.

Initial Value of Form Control is 100
while typing, the % vanishes
returns on blur
value of formControl is without % symbol

Creating the Custom Component

custom-input.component.html

The HTML can have anything, it need not be a form element depending on the requirement. For a star rating component you can have 5 divs with star shape CSS. In that scenario the trigger would be click events instead of input value changes.

The main code to link the form control with any operation on our html content will be in the typescript file of the component.

custom-input.component.ts

We can divide the code as follows —

Dependency Injection of NGRX_FORM_VIEW_ADAPTER:

for the token ‘NGRX_FORM_VIEW_ADAPTER’ we want to provide our existing CustomInputComponent.

ForwardRef is used to handle cases when out component may not have been initialized before use.

multi: true is used because the same token now provides different values.

If you need more clarity on ForwardRef or multi: true there are lots of good articles on the internet. Feel free to Google it out!

Scenario Based Code Section

This can be any logic, its based on your scenario. In our case we need to show a suffix based on focus and value changes so we have methods related to those.

Example code

We are simply binding ‘value’ with ngModel to the native input (this will have the suffix added when required).

The ‘localValue’ keeps the numerical values of the input field without the suffix which is used when we focus into the input. (You can add any validation like allowing only number inputs, in the inputChanged method, for invalid values just make this.value = ‘’)

Adapter Functions

We implement the FormViewAdapter interface that gives us 4 methods

adapter methods

These methods update the formControl value when required based on scenario. In our case the formControl should update when value changes in the input field.

  • setViewValue: This is called when our custom component is first initialized. Use this to get initial value from the FormControl and update the html bindings accordingly.
  • setOnChangeCallback: use the callback function here to update the formControl value as per your scenario. In this case when input changes we will use this callback.
the callback we receive in setOnChangeCallback()

It takes updatedValue from our html and does a setValue on the NgRx FormControl.

Assigning the callback
Using the callback

The Touch and Disable callbacks work similarly. You can refer below official doc link for more info

Parent component using our custom-input

Now we can directly use our ngrxFormControlState with our custom component.

Conclusion

If you go through the official docs, it mentions that NgRx Forms takes care of syncing with third party libraries out of the box by converting controlValueAccessor into FormViewAdapter but it fails in some scenarios.

In the above case or if we have to create our own in house HTML elements that can be used with formControls directly, this article should help you create such components.

Please find GitHub Link below

--

--

Ayush Thakur

Developer, Musician, Biker, Coder & Travel enthusiast