Making Angular Custom Form Components Easier to Work With

Wayne Leung
5 min readJun 8, 2023

--

Angora Forms promises a new and improved workflow when building custom form components in Angular. Let’s dive in and examine the newcomer along with currently existing options.

First, an overview

Angular is a robust and open-source framework used by large companies and organizations such as Google, IBM, and Microsoft. It is popular for building complex enterprise-scale applications due to its comprehensive set of tools, scalability, and performance. Perhaps the standout feature that attracts these larger enterprises is the ‘strict’ or ‘opinionated’ nature of the framework. It prescribes a definitive structure with rules that developers are encouraged to follow. As you can imagine, this helps ensure code quality, maintainability, and scalability.

Angular forms…

Angular provides two different APIs for dealing with forms:

  1. Template-driven forms (TDF) and
  2. Reactive forms (RF)

TDFs are quite straightforward and are useful for adding a simple form to an app, such as an email list signup form. They are easy to add to an app, but they don’t scale as well as RFs because the design:

  1. does not handle complexity well. For example, nested forms, dynamic forms, or forms with complex validation logic;
  2. is not easily testable. The form model is defined in the template, so the developer will need to create a test host component to wrap around the form component in order to test it;
  3. does not support asynchronous validation directly;
  4. makes it difficult to control complex logic because it relies on directives and mutable data models; and
  5. abstracts away the underlying form control objects by directives in the template. This makes it hard to manipulate form control objects directly, which can limit the amount of control the developer has over their forms.

Reactive forms address these issues and provide flexibility and customizability. However, it comes with a considerable amount of boilerplate code.

Component logic:

HTML template:

And this is only for a single custom form component.

Workflow 1 — NativeScript (existing)

One way to manage this is to create a base class, such as ‘ValueAccessorBase’, which implements the ‘ControlValueAccessor’ interface and has the custom form controls extend this base class. The common boilerplate code can then be reused across multiple components.

To create the abstraction logic:

From there on, each component can inherit boilerplate code from ValueAccessorBase class:

In the code above, ‘CustomControlComponent’ extends ‘ValueAccessorBase’, effectively inheriting its functionality. This eliminates the necessity to re-implement the ‘ControlValueAccessor’ methods in each custom control component, reducing boilerplate.

However, although ‘BaseValueAccessor’ is a part of Angular, it is specifically a part of NativeScript-Angular (NS-A).

NativeScript is an open-source framework for building native mobile applications with Angular. ‘BaseValueAccessor’ is a class in NS-A that creates a bridge between Angular’s forms API and NativeScript’s UI components. It is not part of standard Angular for web development and is used in NS-A to facilitate the use of Angular’s forms with NativeScript’s UI components.

While Angular is a platform-agnostic framework and can be used to build applications for a variety of platforms including web, mobile and desktop, the specific classes or components from certain libraries might not be. Therefore it may not the ideal solution.

Workflow 2 — ngspot/ng-superclass (existing)

ngspot/ng-superclass is a library of classes that aid in simplifying writing Angular components or directives and custom controls that implement ControlValueAccessor. It boasts boilerplate abstractions in the form of the following:

  1. FormComponentSuperclass — which allows developers to create simple or complex custom form controls,
  2. DirectSuperclass — for getting streams of @Input values, and
  3. SubscribeSink — for automatic subscription management

Image credit: @ngspot/ng-superclass

FormComponentSuperclass aims to abstract boilerplate code, smoothen out edge cases and free developers to focus strictly on the handling of control values.

Ng-superclass provides a great solution that keeps the code DRY by reducing much of the boilerplate code necessary for Angular. However, a considerable amount of boilerplate code is still required for each custom component and each component still requires its own file to handle its template and logic, making it less than ideal to handle and maintain forms with larger numbers of custom components.

Workflow 3 — Angora Forms (new)

Angora Forms (AF) is a new custom form component abstraction library designed for Angular which aims to streamline and simplify the process of creating custom form components. Its design philosophy has an advantage over the other two methods in that it requires the least amount of boilerplate code and retains all the customizability and control of custom components that utilize Angular’s own ControlValueAccessor. It also introduces a great way to consolidate all the business logic and templates of custom form components into one file, making the code readable and reviewable.

That’s it.

For more than one custom form component:

As we can see, it is quite minimal and makes control logic quite easy to manipulate and maintain.

One downside with AF at the time of writing is that it requires a bit of initial setting up (such as webpack config) before the streamlined workflow is integrated.

AF also has a companion form builder web application that speeds up the process of building Angular forms. It features the ability to save and retrieve created forms and form components for reusability.

In conclusion,

It is safe to say that each method has its own set of advantages and disadvantages that make them ideal for different types of projects and workflows. With the introduction of Angora Forms, developers now have an option that gives them an even greater degree of abstraction while maintaining all customizability.

--

--