Form Fatale: How Akita’s Form Manager Can Do Away with Complex Multistep Form Logic in Angular

Inbal Sinai
Netanel Basal
Published in
4 min readMar 20, 2019

--

When it comes to maintaining a multistep form in your application, it can turn into quite a big headache, as any step or combination of steps can affect others, and you need to have real-time knowledge of both the form’s overall validity as well as each step’s status.

But not when you have Akita! Apart from being one of the leading state management libraries, with over 240K downloads to date, Akita has an additional library, AkitaNgFormsManager, which offers form-specific functionality that can significantly simplify your form management experience.

The AkitaNgFormsManager lets you sync Angular’s formGroup, formControl, and formArray, via a unique store created for that purpose. The store will hold the controls' data such as values, validity, pristine status, errors, etc. Unlike other libraries, this form manager doesn’t require the user to learn a brand new API; Instead, it relies on the existing Angular forms API.

Let’s take a look at a multi-step form and see how we can use AkitaNgFormsManager with it and what benefits we get from that. We won’t use the entire library API, but you can read about all the available methods here.

Form Value Persistence via a Single API Call

For this example we create a form with three steps; The first will ask for the user’s name and email, the second for details in the user’s address, and the third will ask for the user’s children’s names. We store each step in our AkitaNgFormsManager store separately, by using the library’s upsert method.

Here’s how the form management looks like when we inspect the store in Redux DevTools:

Step one:

Step two:

Step three:

This isn’t your regular run-of-the-mill upsert method —it inserts the form in AkitaNgFormsManager’s store if a form by that name doesn’t already exist for the given key, but if it does, it updates the component’s newly created form with the values and fields already stored for the existing form. This ensures that the changes made in each form are preserved even as we leave that form and the component in charge of it is destroyed. And it does that in a single, elegant, API call.

The component in charge of the third step is a bit more clever than a regular form: it adds and removes form fields dynamically, based on the selected number of children. To ensure that the modified FormArray can be recreated the next time the component is initialised, we add a third config parameter in the upsert call, containing a factory function for generating each FormControl in the array. This ensures that upon ensuing visits to the form page, the correct number of fields will be generated based on the form saved in the store.

Tracking Validity via the Store

To keep track of each step’s validity and dirty status we create a directive, ValidStepDirective:

The directive receives as input the form’s key in the store, allowing it to simply observe the required form status values (using the combineLatest operator). In this case, we combine the two values and return false if and only if the form is both dirty and invalid. The result controls whether the host element receives the “invalid” class, allowing us to signal to the user which step is invalid.

Accessing Form Values via the Store

The parent component also requires each step’s validity status for an additional reason: Since these are all steps of a single form, the parent component, OnBoardingComponent, holds the single submission button for the entire form, enabled only when all steps are valid:

Once again, simply by accessing the store, OnBoardingComponent can easily determine the overall validity of the form at any given moment. And upon submission, it gets each step’s form value from the store in order to submit it to the server (or in our example’s case, log it in the console).

Here’s the end result:

In summary: Managing the state of complex, multi-step forms, has never been easier. AkitaNgFormsManager takes care of all the boilerplate needed to consistently deliver each step’s values, as well as track its validity and dirty status.

Here are some more articles about Akita:

Follow me on Medium to read more about Angular, Akita, JS!

--

--

I'm a front-end developer at Palo Alto Networks and a blogger. Passionate about code, photography and pizza.