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
FormControlrepresents one field, such as a name box.FormGroupcollects several controls into one form.FormArrayholds a list of controls that can grow or shrink.Validatorssupplies 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
| Point | Template Forms | Reactive Forms |
|---|---|---|
| Where rules live | In the HTML | In the class |
| Best for | Small, simple forms | Large, dynamic forms |
| Testing | Harder | Easier |
| Control level | Basic | Full |
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.
