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 FormGroup
s are one of those many benefits.
Top comments (0)