Dynamic Forms in Angular with FormArray

Cover image

This is the first part of the series describing the way Angular deals with dynamic and nested reactive forms

Someone said that modern web apps are basically just forms and lists. If lists are easy to grasp for any software craftsman, forms can be tough, especially if you work with some web-development framework and its opinionated patterns and tools. The topic becomes even more interesting and complicated if talk about dynamic forms, that is:

  1. when the form configuration object is passed from outside, and the app builds the UI based on that (using corresponding predefined setup and restrictions), or
  2. when user manages how many form controls the resulting form will have using CRUD controls.

In this post we are going to discuss how Angular approaches this challenge and what dedicated out-of-the-box tools does it provide to a developer.

Prerequisites

Though I try to explain the topic of dynamic forms here in a simple and concise way, this is a kind of advanced tutorial. I assume that you have at least basic understanding of HTML (and forms in particular), CSS, JavaScript and TypeScript mechanics, and can reason about Angular application development on a level of the official starter tutorial.

I will not dive into differences between Template-Driven and Reactive Forms, Reactive Forms internals, form validation, error handling, form config type safety or form testing within the scope of this post as I try to make it short and narrow-focused. So it's also a good idea to have a basic grasp on these topics as a background (or consider digging deeper into the list in future).

Finally, we are going to work within a single component for brevity purposes and to make it more visual. The next part of the series is dedicated to form component decomposition.

Case Study

We will develop a tiny simple Contact Form app which need to have a set of dynamically added/removed form fields (for phone numbers and email addresses).

The initial setup for this app is available at this blitz so you could play around with the code and try the described concepts yourself.

Solution

To give life to our simple HTML structure and make UI controls interactive we are going to use ReactiveFormsModule and some of its important building blocks: FormBuilder, FormGroup, FormArray and FormControl.

FormBuilder service allows us to compile a basic form structure inside the app component.

FormGroup class provides a skeleton for the form and its counterparts, and delivers this contraption to the UI layer using FormControl bindings.

The trickiest part of the UI is dynamic input field (FormGroup or FormControl) adding and removing for phones and emails. We are going to build this feature using FormArray class, which provides a scaffolding for homogenous FormGroup combinations. It gives us everything we need to develop CRUD functionality for repetitive form patterns.

The diagram shows the simplified app structure and the role of all these building blocks in it.

...

For demo purposes we use very simple data structure here, but as you might guess, we could easily expand any of its parts, as well as the corresponding form group structure. For instance, we could add some kind of select control for phone number group of phones array (to describe its type, for instance), or add a checkbox control for email form group to make it hidden if we chose to.

Summary

The final solution is available at this blitz.