Reactive Forms Benefits: Nested Form Groups

Posted on July 17, 2020

Written by Preston Lamb

angular reactive forms

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" /> 
		</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.

Click here to subscribe to the newsletter and be the notified when a new blog post is available!