Skip to content
advanced Phase 7 · Reactive Forms and Validation

Nested Groups and Model Mapping

Mirror nested API objects with grouped form controls.

40m
0 problems
Topic Progress 0%

Nested FormGroups

Nested FormGroups mirror nested object shapes, keeping form structure aligned with your data model.

Creating Nested Groups

this.form = this.fb.group({
  firstName: ['', Validators.required],
  lastName: ['', Validators.required],
  email: ['', [Validators.required, Validators.email]],
  address: this.fb.group({
    street: [''],
    city: [''],
    state: [''],
    zip: ['', Validators.pattern(/^\d{5}$/)],
  }),
});

Template with Nested Groups

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input formControlName="firstName" placeholder="First name">
  <input formControlName="lastName" placeholder="Last name">
  <input formControlName="email" placeholder="Email">

  <div formGroupName="address">
    <input formControlName="street" placeholder="Street">
    <input formControlName="city" placeholder="City">
    <input formControlName="state" placeholder="State">
    <input formControlName="zip" placeholder="ZIP">
  </div>

  <button type="submit">Save</button>
</form>

Accessing Nested Controls

// Get a nested control
const cityControl = this.form.get('address.city');

// Get the nested group
const addressGroup = this.form.get('address') as FormGroup;

// Check nested validity
const isAddressValid = this.form.get('address')?.valid;

setValue vs patchValue with Nested Forms

// setValue — must provide ALL controls including nested
this.form.setValue({
  firstName: 'Alice',
  lastName: 'Smith',
  email: 'alice@example.com',
  address: {
    street: '123 Main St',
    city: 'Springfield',
    state: 'IL',
    zip: '62701',
  },
});

// patchValue — only update specified controls
this.form.patchValue({
  email: 'alice@newemail.com',
  address: {
    city: 'Chicago',
  },
});

Mapping API DTOs to Form Models

Mapping between API DTOs and form models keeps transport concerns out of template code.

API DTO Interface

interface UserDto {
  id: number;
  firstName: string;
  lastName: string;
  email: string;
  address: {
    street: string;
    city: string;
    state: string;
    zip: string;
  };
  preferences: {
    newsletter: boolean;
    theme: 'light' | 'dark';
  };
}

Loading API Data into the Form

loadUser(id: number): void {
  this.userService.getUser(id).subscribe(user => {
    this.form.patchValue({
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
      address: {
        street: user.address.street,
        city: user.address.city,
        state: user.address.state,
        zip: user.address.zip,
      },
      preferences: {
        newsletter: user.preferences.newsletter,
        theme: user.preferences.theme,
      },
    });
  });
}

Submitting Form Data to API

onSubmit(): void {
  if (!this.form.valid) {
    this.form.markAllAsTouched();
    return;
  }

  const formValue = this.form.value;

  const userDto: UserDto = {
    id: this.userId,
    firstName: formValue.firstName,
    lastName: formValue.lastName,
    email: formValue.email,
    address: {
      street: formValue.address.street,
      city: formValue.address.city,
      state: formValue.address.state,
      zip: formValue.address.zip,
    },
    preferences: {
      newsletter: formValue.preferences.newsletter,
      theme: formValue.preferences.theme,
    },
  };

  this.userService.updateUser(this.userId, userDto).subscribe({
    next: () => this.showSuccess('Profile updated'),
    error: (err) => this.showError(err.message),
  });
}

Deeply Nested Forms

this.form = this.fb.group({
  // ... other fields
  shippingAddress: this.fb.group({
    street: [''],
    city: [''],
    country: this.fb.group({
      code: [''],
      name: [''],
    }),
  }),
});
<div formGroupName="shippingAddress">
  <input formControlName="street">
  <div formGroupName="country">
    <input formControlName="code">
    <input formControlName="name">
  </div>
</div>

Quiz

1. How do you access a nested form control?

Question 1 options

2. What is the difference between setValue and patchValue?

Question 2 options

3. Why map API DTOs to form models?

Question 3 options

Flashcards

Question

How do you create nested form groups?

Answer

this.fb.group({ address: this.fb.group({ city: [''] }) }) — nest FormGroup inside FormGroup.

Question

setValue vs patchValue?

Answer

setValue requires all controls. patchValue updates only specified controls.

Question

Why map API DTOs to form models?

Answer

Separates transport from UI, provides type safety, and makes forms testable.

Revision Notes

Key Takeaways

  • 1. Nested FormGroups mirror nested object shapes
  • 2. formGroupName binds nested groups in templates
  • 3. setValue requires all controls; patchValue is partial
  • 4. Map API DTOs to form models for type safety

Interview Tips

  • • Explain how nested groups align with data models
  • • Be ready to describe setValue vs patchValue
  • • Mention DTO mapping for clean architecture

Cheat Sheet

Nested Forms Cheat Sheet

Nested group:

this.fb.group({
  address: this.fb.group({
    city: [''],
  }),
});

Template:

<div formGroupName="address">
  <input formControlName="city">
</div>

Access nested control:

this.form.get('address.city');

setValue vs patchValue:

  • setValue: all controls required
  • patchValue: partial updates only

Continue Learning