← Back to Chapters

FormGroup & Nested Forms

? FormGroup & Nested Forms

Angular Reactive Forms

? Quick Overview

In Angular reactive forms, a FormGroup is used to group related form controls into a single object. Nested FormGroup structures let you create hierarchical, real-world forms such as user profiles, addresses, and multi-section wizards.

? Key Concepts

  • FormGroup represents a collection of named FormControl objects.
  • Form values are exposed as a single JavaScript object (e.g. userForm.value).
  • Nested FormGroup objects help you mirror structured data like address, profile, etc.
  • In templates, [formGroup] binds the root group, and formGroupName binds nested groups.
  • Validation works at control level, nested group level, and parent group level.

? Syntax & Structure

A basic FormGroup is created in the component class using the reactive forms API, then bound to a <form> element in the template:

? View Code Example (FormGroup Structure)
// Create a FormGroup with a nested address group
userForm = new FormGroup({
  name: new FormControl(''),
  email: new FormControl(''),
  address: new FormGroup({
    street: new FormControl(''),
    city: new FormControl(''),
    zip: new FormControl('')
  })
});

? Basic FormGroup Example (Component)

A simple form with name and email controls using FormGroup.

? View Code Example
// app.component.ts - Basic FormGroup example
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // Group name and email controls into a single userForm FormGroup
  userForm = new FormGroup({
    name: new FormControl('', [Validators.required]),
    email: new FormControl('', [Validators.required, Validators.email])
  });

  submitForm() {
    // Handle form submission and log all form values
    console.log('Form Submitted', this.userForm.value);
  }
}

?️ Nested FormGroup Example (Component)

Extend the form to include a nested address group inside userForm.

? View Code Example
// app.component.ts - Nested FormGroup with address
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // Root FormGroup with a nested address FormGroup
  userForm = new FormGroup({
    name: new FormControl('', [Validators.required]),
    email: new FormControl('', [Validators.required, Validators.email]),
    address: new FormGroup({
      street: new FormControl('', Validators.required),
      city: new FormControl('', Validators.required),
      zip: new FormControl('', Validators.required)
    })
  });

  submitForm() {
    // Log both top-level and nested values as a single object
    console.log('Form Submitted', this.userForm.value);
  }
}

? Nested FormGroup Example (Template)

Bind the root FormGroup and nested address group in the HTML template.

? View Code Example
<!-- app.component.html - Template for nested FormGroup -->
<form [formGroup]="userForm" (ngSubmit)="submitForm()">
  <label>Name:</label>
  <input type="text" formControlName="name">
  <br><br>

  <label>Email:</label>
  <input type="email" formControlName="email">
  <br><br>

  <div formGroupName="address">
    <!-- Nested group for address fields -->
    <label>Street:</label>
    <input type="text" formControlName="street">
    <br><br>

    <label>City:</label>
    <input type="text" formControlName="city">
    <br><br>

    <label>ZIP:</label>
    <input type="text" formControlName="zip">
    <br><br>
  </div>

  <button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>

? Live Output & Explanation

What happens when you use this form?

  • FormGroup collects values from all child controls into one object like: { name, email, address: { street, city, zip } }.
  • The formGroupName="address" directive tells Angular that the inner controls belong to the nested address group.
  • Validation is applied to each control. If any required field is empty, userForm.invalid becomes true and the Submit button is disabled.
  • On submit, submitForm() runs, and this.userForm.value logs the complete form data (including the nested address object) to the console.

? Common Use Cases

  • User profile forms with nested sections (personal info, contact info, address, preferences).
  • Checkout forms with billing and shipping addresses as separate FormGroup objects.
  • Multi-step wizards where each step is its own FormGroup, combined into a parent group.

✅ Tips & Best Practices

  • Use nested FormGroup objects whenever your data model is also nested (e.g. user.address.city).
  • Access nested controls safely using: this.userForm.get('address.street') in the component class.
  • Combine FormGroup with Validators to enforce rules on both parent and child controls.
  • Use meaningful group names like address, profile, or paymentDetails so that userForm.value matches your backend DTO/interface.

? Try It Yourself

  • Create a registration form with a root FormGroup containing user info and a nested address group.
  • Add validation for street, city, and zip fields (all required).
  • On submission, log the full form value and try reading a single nested control using this.userForm.get('address.city')?.value.
  • Extend the nested group with an optional country control and set a default value like 'India'.