Reactive forms

Reactive forms are model-driven: you define the form structure and validation logic in your TypeScript code, then bind it to the template. They are more powerful and scalable than template-driven forms.


1️⃣ Import ReactiveFormsModule

In app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';   // ✅ import this
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ReactiveFormsModule   // ✅ add here
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2️⃣ Define Form in Component

In app.component.ts:

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  
  myForm!: FormGroup;   // declare form

  ngOnInit() {
    this.myForm = new FormGroup({
      name: new FormControl('', [Validators.required, Validators.minLength(3)]),
      email: new FormControl('', [Validators.required, Validators.email]),
      age: new FormControl('', [Validators.required, Validators.min(18)])
    });
  }

  onSubmit() {
    console.log('Form Value:', this.myForm.value);
    console.log('Form Valid:', this.myForm.valid);
  }
}

3️⃣ Create Template

In app.component.html:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">

  <div>
    <label for="name">Name:</label>
    <input id="name" type="text" formControlName="name" />
    <div *ngIf="myForm.get('name')?.invalid && myForm.get('name')?.touched" style="color:red">
      <span *ngIf="myForm.get('name')?.errors?.['required']">Name is required.</span>
      <span *ngIf="myForm.get('name')?.errors?.['minlength']">Name must be at least 3 characters.</span>
    </div>
  </div>

  <div>
    <label for="email">Email:</label>
    <input id="email" type="email" formControlName="email" />
    <div *ngIf="myForm.get('email')?.invalid && myForm.get('email')?.touched" style="color:red">
      <span *ngIf="myForm.get('email')?.errors?.['required']">Email is required.</span>
      <span *ngIf="myForm.get('email')?.errors?.['email']">Enter a valid email.</span>
    </div>
  </div>

  <div>
    <label for="age">Age:</label>
    <input id="age" type="number" formControlName="age" />
    <div *ngIf="myForm.get('age')?.invalid && myForm.get('age')?.touched" style="color:red">
      <span *ngIf="myForm.get('age')?.errors?.['required']">Age is required.</span>
      <span *ngIf="myForm.get('age')?.errors?.['min']">You must be at least 18 years old.</span>
    </div>
  </div>

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

4️⃣ Key Differences (Reactive vs Template-Driven)

FeatureTemplate-DrivenReactive
Form ModelDefined in templateDefined in TypeScript
SetupSimpler, less codeMore structured
ValidationUses directives (required, email, etc.)Uses Validators class in TS
Best ForSimple formsComplex, dynamic, testable forms
TestingHarderEasier

Leave a Reply