← Back to Chapters

Reactive Forms Basics

⚙️ Reactive Forms Basics

? Quick Overview

Reactive forms in Angular provide a code-driven way to build and manage forms. Instead of defining form logic only in the template, you configure form structure, validation, and state in the TypeScript class using FormGroup and FormControl. This makes reactive forms ideal for complex, dynamic, and highly validated form scenarios.

? Best for complex & dynamic forms

? Key Concepts

  • FormGroup – a collection of form controls, representing the whole form or a logical group.
  • FormControl – represents a single input field and holds its value and validation state.
  • Validators – functions like Validators.required or Validators.email that enforce rules.
  • Immutable state – every change to a control creates a new state, making it predictable and easy to debug.
  • Template binding – the form is connected to the template using the [formGroup] and formControlName directives.

? Syntax & Theory

To use reactive forms, you must first import ReactiveFormsModule into your Angular root or feature module. Then, in your component, you define a FormGroup instance with one or more FormControl objects.

In the template, you bind the FormGroup instance to the form element using [formGroup], and each field is bound using formControlName. Angular automatically keeps the form model and the view in sync.

? Code Example: Setting Up Reactive Forms

First, enable reactive forms support in your Angular module:

? View Code Example (app.module.ts)
// app.module.ts - register ReactiveFormsModule
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, ReactiveFormsModule],
  bootstrap: [AppComponent]
})
export class AppModule {}

? Basic Reactive Form Example

This example creates a simple user form with name and email fields and basic validation.

? View Code Example (app.component.ts)
// app.component.ts - reactive user form definition
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 {
  userForm = new FormGroup({
    name: new FormControl('', [Validators.required, Validators.minLength(3)]),
    email: new FormControl('', [Validators.required, Validators.email])
  });

  submitForm() {
    console.log('Form Submitted', this.userForm.value); // Log the form values when the form is valid
  }
}
? View Code Example (app.component.html)
<!-- app.component.html - bind the FormGroup to the template -->
<form [formGroup]="userForm" (ngSubmit)="submitForm()">
  <label>Name:</label>
  <input type="text" formControlName="name">
  <div class="error" *ngIf="userForm.get('name')?.errors && userForm.get('name')?.touched">
    <span *ngIf="userForm.get('name')?.errors?.required">Name is required.</span>
    <span *ngIf="userForm.get('name')?.errors?.minlength">Name must be at least 3 characters.</span>
  </div>
  <br><br>

  <label>Email:</label>
  <input type="email" formControlName="email">
  <div class="error" *ngIf="userForm.get('email')?.errors && userForm.get('email')?.touched">
    <span *ngIf="userForm.get('email')?.errors?.required">Email is required.</span>
    <span *ngIf="userForm.get('email')?.errors?.email">Invalid email format.</span>
  </div>
  <br><br>

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

? Live Output & Explanation

What Happens When You Use This Form?

  • Initially, the Submit button is disabled because the form is invalid.
  • When you type in the Name field:
    • If it is empty, you see "Name is required.".
    • If it has fewer than 3 characters, you see "Name must be at least 3 characters.".
  • When you type in the Email field:
    • If it is empty, you see "Email is required.".
    • If the format is wrong, you see "Invalid email format.".
  • Once both fields are valid, the button becomes enabled and clicking it calls submitForm(), logging the form values in the browser console.

✅ Tips & Best Practices

  • Use reactive forms for complex, dynamic, or highly validated form scenarios.
  • Always import ReactiveFormsModule in the appropriate module (e.g., app.module.ts).
  • Access controls using userForm.get('controlName') to read values, check validity, or subscribe to value changes.
  • Use touched and dirty states to avoid showing error messages before the user interacts with a field.
  • Keep all validation logic in the TypeScript file for better testability and maintainability.

? Try It Yourself

  • Create a login form using reactive forms with email and password controls.
  • Add a password field with required and minLength(6) validators.
  • Show live validation messages as the user types, similar to the example above.
  • Add a rememberMe checkbox as a FormControl and log its value when the form is submitted.
  • Experiment with disabling the submit button until the form is valid using [disabled]="loginForm.invalid".