Reactive Forms Benefits: Nested Form Groups

Written by Preston Lamb

Posted on Jul 17, 2020

angularreactive forms

Make sure to check out the other posts in this series:

Getting Started with Deno

Learn how to start using Deno with my brand new course!

Buy the Course

tldr;

Many times when trying to collect data from users, the forms can get complex. It can be hard to know how to collect the data, and do so in the simplest manner, but I've found that reactive forms in Angular make it easier than I thought. In this post, we'll look at an example I recently came upon at work and how easy it was to solve with reactive forms.

Background

I work for a health insurance company, and I needed to collect some information about a member and the people on their policy. Part of the requirement for the form was to select checkboxes next to each person on the policy to say if the information entered applied to them. I started thinking about how to go about this, knowing I couldn't hard-code anything because every policy is different. I had an Observable that gave me an array of the people on the policy, so I knew I could loop over that array to output the checkboxes, but I didn't know how to get the values from those checks into the form.

Solution

The solution turned out to be pretty simple. All I needed to do was to make one of the controls in my FormGroup have the value of another FormGroup. It ended up looking like this (in part):

this.memberService.memberFamilyArray$
    .pipe(
        tap((family: Person[]) => {
            this.informationForm = this._formBuilder.group({
                affectedPolicyMembers: this._formBuilder.group(
                    family.reduce((group: any, person: Person) => {
                        group[person.id] = null;
                        return group;
                    }),
                ),
            });
        }),
    )
    .subscribe();

What's happening here is that the top level form has an attribute affectedPolicyMembers. The value of that control is another FormGroup. The FormGroup is created by using the reduce method on the family array. Each family member has an id, so I added each ID as a key on the object and set the initial value to null. This got the form set up properly, but the next step was how to output the form controls in the HTML. Here's what I ended up doing:

<form [formGroup]="informationForm">
    <div formGroupName="affectedPolicyMembers">
        <label *ngFor="let member of memberFamilyArray$ | async">
            <input [formControlName]="member.id" type="checkbox" /> {{ member.firstName }}
        </label>
    </div>
</form>

This looks pretty straight-forward as far as reactive forms go, but notice that on the div right below the form element there's an attribute called formGroupName. That's where the affectedPolicyMembers attribute from the informationForm goes. Then inside that div you can use the nested form group's attributes. In this case, there's one attribute for each member on the policy, and the key is the member's ID.

Conclusion

This would have been a lot harder to correctly capture the information without a reactive form. Not only was I able to capture the data just by boxes being checked, I was also able to add custom validation to the affectedPolicyMembers group. Reactive forms in Angular have a lot of benefits, and nested FormGroups are one of those many benefits.

Getting Started with Deno

Learn how to start using Deno with my brand new course!

Buy the Course