Angular Reactive Forms

Reactive forms build the form structure in TypeScript code instead of the template. You describe every field, rule, and message in the class, and the template simply displays them. This style gives you full control over complex forms, such as sign-up pages with many rules. It also makes forms easy to test.

The Blueprint Idea

An architect draws a blueprint before builders start work. A reactive form follows the same plan. You draw the form in code first, and then you connect it to the page. The code stays the main source of truth.

+----------------------+       +----------------------+
|  Component class     |       |  Template (HTML)     |
|                      |       |                      |
|  FormGroup           | ----> |  <form [formGroup]>  |
|   - name  (control)  |       |  <input formControl> |
|   - email (control)  |       |                      |
+----------------------+       +----------------------+

Main Building Blocks

  • FormControl represents one field, such as a name box.
  • FormGroup collects several controls into one form.
  • FormArray holds a list of controls that can grow or shrink.
  • Validators supplies ready-made rules such as required and minimum length.

Create a Simple Form

Import ReactiveFormsModule into your component. Build the group in the class.

import { Component } from '@angular/core';
import { ReactiveFormsModule, FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-signup',
  imports: [ReactiveFormsModule],
  templateUrl: './signup.component.html'
})
export class SignupComponent {
  signupForm = new FormGroup({
    name: new FormControl('', Validators.required),
    email: new FormControl('', [Validators.required, Validators.email])
  });

  submit() {
    console.log(this.signupForm.value);
  }
}

Connect the Form to the Template

<form [formGroup]="signupForm" (ngSubmit)="submit()">
  <input formControlName="name" placeholder="Name">
  <input formControlName="email" placeholder="Email">
  <button type="submit" [disabled]="signupForm.invalid">Join</button>
</form>

The formGroup property links the form element to the class. Each formControlName links one input to one control. The button stays disabled until every rule passes.

Show Validation Messages

Each control reports its own state. The touched state becomes true after a visitor leaves the field. Check it to avoid showing errors too early.

@if (signupForm.controls.email.touched && signupForm.controls.email.invalid) {
  <p>Enter a valid email address.</p>
}

Read and Change Values

The value property returns all field values together. The setValue method replaces every value, and patchValue replaces only the fields you name. The reset method clears the form.

this.signupForm.patchValue({ name: 'Asha' });
this.signupForm.reset();

Custom Validators

A custom validator is a function that checks a rule that Angular does not provide. It returns null when the value passes and an error object when it fails.

import { AbstractControl, ValidationErrors } from '@angular/forms';

export function noSpaces(control: AbstractControl): ValidationErrors | null {
  const hasSpace = (control.value || '').includes(' ');
  return hasSpace ? { noSpaces: true } : null;
}

Template Forms Compared with Reactive Forms

PointTemplate FormsReactive Forms
Where rules liveIn the HTMLIn the class
Best forSmall, simple formsLarge, dynamic forms
TestingHarderEasier
Control levelBasicFull

Form Status Values

Every control and group reports its health through simple properties. The valid property turns true when all rules pass. The invalid property turns true when any rule fails. The dirty property turns true after the visitor changes a value. The pristine property stays true while the value remains untouched. Combine these properties to decide when to show messages or enable buttons. A common pattern shows an error only when the field is both invalid and touched.

Watch Value Changes

Each control exposes a valueChanges stream. Subscribe to it when the page must react while the visitor types. A search box uses this stream to load suggestions after each keystroke. Remember to unsubscribe when the component closes, or use the async pipe to handle that task for you.

Grouping Nested Fields

A form group can contain another form group. An address section with street, city, and postal code fits well inside a nested group. The nested group keeps related fields together and lets you validate them as one unit.

Real-Life Example

A job application page asks for contact details and a list of past employers. The visitor adds as many employers as needed. A FormArray stores that growing list, and each entry holds its own small group of fields. The code adds or removes entries with a single method call.

Practice Exercise

Build a login form with an email field and a password field. Require both, and demand at least eight characters for the password. Show a message under each field when a rule fails. Disable the button until the form is valid.

Key Points

  • Reactive forms define fields and rules in the class.
  • FormControl, FormGroup, and FormArray structure the form.
  • Validators enforce rules, and custom validators handle special rules.
  • Use reactive forms for large or changing forms.

Leave a Comment

Your email address will not be published. Required fields are marked *