Author (Using Undraw as a base:

Three ways to create an Angular Custom Form Component

Hi everyone, in this quick article we will look at three different ways to create an Angular Custom Form Component, in both Template-driven declaration and Reactive Forms. We are not going dive into detail about these implementations, however, for each a working example will be provided. We also will discuss some pros and cons of each approach.

This article is heavily based on the Kara Erickson presentation on Angular Connect 2017, so take a look at her explanation if you can.

You gonna need to know something about Angular Forms, both Template-driven declaration and Reactive Forms, and you have to understand, at least to a certain degree, the Angular Dependency Injection.

This is the classic way to create a custom form component. You can find like a hundred tutorials on how to implement it in this way. On the basics, in our target component, we will first implement the ControlValuAccessor interface, with its compulsory methods, and provide our own custom component as aNG_VALUE_ACCESSOR token in the component decorator.

And here is an example of a working form with this implementation.

Now, on the positives and negatives, first the Positives.

  • Positives: It’s well documented. We can find a lot of tutorials on how to create a form like this, and, one of its big strengths, is that we have two main flows of values, the ones that cames from the forms object through the writeValue method, that being NgForm or FormControl, and the values that cames from our custom component through the onChange method, meaning that we can apply different treatments to each flow.
  • Negatives: There are two main problems with this implementation. First, when the component is rendered the writeValue method fires before its view has been initiate, demanding extra attention when calling view references. And second, we are unable to tap the control form object itself, the NgControl. This is one of its major drawbacks, without it we can’t access any values defined in the control, like validators, if the control is disabled, or if has any other state. This means that none of ours form elements, in our custom components view, will able to access the control validators and state if these are declared in the parent component, a necessity that some of the forms I have worked on in the past have presented.

Very similar to the previous implementation, but without providing our own custom component as aNG_VALUE_ACCESSOR, rather it taps the NgControl provided in the host component, being the best method to use. The rest is pretty the same, by setting the attribute valueAccessor with our component, after that implement the ControlValuAccessor interface, like this.

And here is an example of a working form with this implementation.

Now, on the positives and negatives, first the Positives.

  • Positives: Sharing most of the same positives of the last method, the only difference is that this method can access the Form control and its parent Form Group.
  • Negatives: Well, its shares most of the same problems with the previous method, excepts that it can tap in the NgControl.

This one is fun to use but is more circumstantial. The catch here is to allow the Form Control directive to see your form in the father component. This is achieved by providing the ControlContainer using an existing Form Control, this being a NgForm or a FormGroupDirective , depending on if you are using Template-Driven or Reactive forms.

So here is the Template-Driven implementation:

And here is the Reactive Forms implementation:

And here are working examples for both Template-Driven and Reactive.

Now, on the positives and negatives, first the Positives.

  • Positives: It has a very clear implementation, posses the ability to access the form validations, and has the potential to encapsulate the control implementation in the custom form component, so we can make that our components add the control to the form group, or remove it;
  • Negatives: The implementation only works for the NgForm or for the FormGroupDirective , not both, and here we don’t have two different pipes of values.

So, which one we should use? Well, without thinking too much, accessing the Form Control method has the best positives and misses the worts negatives. So, in my opinion, the second method it’s a solid choice. But, if the situation demands a different type o value accessor provider we should consider the first method, or if we need to control more the form control object, the third method would be the best choice.

As we can see, Angular provides a good number of options so we can create fine-tuned form components. Thank you all for reading, and until next time.