Forms are an important part of any website or app. They allow us to enter important information like usernames, email addresses, phone numbers, etc. Businesses and organizations always need visitors’ details to convert them into customers. Angular provides two main approaches for handling forms: reactive forms and template-driven forms. Both approaches take input from the users using view and complete the data validation. Later, they update the form from a data model and provide a way to monitor all the changes made by the user.

Reactive Forms in Angular
Reactive Forms is an approach where forms are built programmatically in Angular. Unlike the template-driven forms, which work on an HTML template, Reactive Forms are built in the TypeScript code. Reactive Forms give us more control over form validation and data handling.
Key Features of Reactive Approach
- Programmatic Form Creation: It allows us to have programmatic control over form components. We can define form controls using Form Control, Form Group, and Form Array.
- Synchronous Updates: Forms input and validation are updated in real time.
- Scalability: Best suited for complex forms with many fields or dynamic structures.
- Advance Validation: support both built-in and custom validators. Custom validation helps us to make a complex validation form.
- Form Control States:
- Valid: This means when the user enters the correct details.
- Invalid: When the user enters the wrong information, and the form throws an error.
- Touched: Field was interacted with.
- Dirty: When the user changes the input field value.
Handling Forms with Reactive Approach
Reactive Forms in Angular are a model-driven approach. This approach offers better control over form validation, dynamic changes, and scalability compared to template-driven forms.
Steps to Create a Reactive Form in Angular
1️. Import ReactiveFormsModule
First, import ReactiveFormsModule
in your app.module.ts
:
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], // Add ReactiveFormsModule
bootstrap: [AppComponent]
})
export class AppModule {}
2️. Define the Form in TypeScript
In app.component.ts
, create a FormGroup
with form controls:
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
// Create FormGroup
myForm = new FormGroup({
name: new FormControl('', [Validators.required, Validators.minLength(3)]), // Name field with validation
email: new FormControl('', [Validators.required, Validators.email]), // Email field with validation
password: new FormControl('', [Validators.required, Validators.minLength(6)])
});
// Handle Form Submission
onSubmit() {
console.log('Form Submitted:', this.myForm.value);
}
}
3️. Create the Form in HTML
In app.component.html
, bind the form to the component using formGroup
:
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<!-- Name Input -->
<label for="name">Name:</label>
<input type="text" id="name" formControlName="name" />
<div *ngIf="myForm.get('name')?.invalid && myForm.get('name')?.touched">
<small *ngIf="myForm.get('name')?.errors?.required">Name is required.</small>
<small *ngIf="myForm.get('name')?.errors?.minlength">Must be at least 3 characters.</small>
</div>
<!-- Email Input -->
<label for="email">Email:</label>
<input type="email" id="email" formControlName="email" />
<div *ngIf="myForm.get('email')?.invalid && myForm.get('email')?.touched">
<small *ngIf="myForm.get('email')?.errors?.required">Email is required.</small>
<small *ngIf="myForm.get('email')?.errors?.email">Invalid email format.</small>
</div>
<!-- Password Input -->
<label for="password">Password:</label>
<input type="password" id="password" formControlName="password" />
<div *ngIf="myForm.get('password')?.invalid && myForm.get('password')?.touched">
<small *ngIf="myForm.get('password')?.errors?.required">Password is required.</small>
<small *ngIf="myForm.get('password')?.errors?.minlength">Must be at least 6 characters.</small>
</div>
<!-- Submit Button -->
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
Features of Reactive Forms
✔ Better validation handling
✔ Easier to manage complex forms
✔ Supports dynamic form controls
✔ Easier testing
Validators in Reactive Forms (Angular)
Angular Reactive Forms provide built-in validators and allow you to create custom validators for complex validation logic.
1. Built-in Validators
Angular provides several built-in validators under the Validators
class.
Common Built-in Validators
Validator | Description |
Validators.required | Field must not be empty |
Validators.minLength(length) | Minimum character length |
Validators.maxLength(length) | Maximum character length |
Validators.pattern(regex) | Must match a specific pattern |
Validators.email | Ensures a valid email format |
Validators.min(value) | Minimum number allowed |
Validators.max(value) | Maximum number allowed |
Example: Applying Built-in Validators
Modify app.component.ts
:
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
myForm = new FormGroup({
name: new FormControl('', [Validators.required, Validators.minLength(3)]),
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.minLength(6)]),
age: new FormControl('', [Validators.required, Validators.min(18), Validators.max(60)]),
});
onSubmit() {
console.log('Form Data:', this.myForm.value);
}
}
Displaying Validation Errors in HTML
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<input type="text" formControlName="name" placeholder="Enter Name" />
<div *ngIf="myForm.get('name')?.invalid && myForm.get('name')?.touched">
<small *ngIf="myForm.get('name')?.errors?.required">Name is required.</small>
<small *ngIf="myForm.get('name')?.errors?.minlength">Minimum 3 characters required.</small>
</div>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
2. Custom Validators
If the built-in validators are not enough, you can create your custom validators.
Example: Custom Validator for Strong Password
A strong password must contain at least one uppercase letter, one digit, and one special character.
Step 1: Create a Custom Validator Function
Create a new file password.validator.ts
:
import { AbstractControl, ValidationErrors } from '@angular/forms';
export function strongPasswordValidator(control: AbstractControl): ValidationErrors | null {
const password = control.value;
if (!password) return null; // If empty, let required validator handle it.
const strongPasswordRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$/;
return strongPasswordRegex.test(password) ? null : { weakPassword: true };
}
Step 2: Apply the Custom Validator
Modify app.component.ts
:
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { strongPasswordValidator } from './password.validator';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
myForm = new FormGroup({
password: new FormControl('', [Validators.required, strongPasswordValidator]),
});
}
Step 3: Display Validation Messages in HTML
<input type="password" formControlName="password" placeholder="Enter Password" />
<div *ngIf="myForm.get('password')?.invalid && myForm.get('password')?.touched">
<small *ngIf="myForm.get('password')?.errors?.required">Password is required.</small>
<small *ngIf="myForm.get('password')?.errors?.weakPassword">
Password must have at least 1 uppercase, 1 number, and 1 special character.
</small>
</div>
3. Async Validators (For API Validation)
If you need to validate a field asynchronously, like checking if an email is already taken, you can use async validators.
Example: Async Validator to Check if Email Exists
Create a new file email.validator.ts
:
import { AbstractControl } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { delay, map } from 'rxjs/operators';
// Simulate an API call
const existingEmails = ['test@example.com', 'user@email.com'];
export function emailExistsValidator(control: AbstractControl): Observable<{ emailTaken: true } | null> {
return of(existingEmails.includes(control.value)).pipe(
delay(1000), // Simulate network delay
map(exists => (exists ? { emailTaken: true } : null))
);
}
Apply it in app.component.ts
:
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { emailExistsValidator } from './email.validator';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
myForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email], [emailExistsValidator]),
});
}
HTML:
<input type="email" formControlName="email" placeholder="Enter Email" />
<div *ngIf="myForm.get('email')?.invalid && myForm.get('email')?.touched">
<small *ngIf="myForm.get('email')?.errors?.required">Email is required.</small>
<small *ngIf="myForm.get('email')?.errors?.email">Invalid email format.</small>
<small *ngIf="myForm.get('email')?.errors?.emailTaken">Email already exists.</small>
</div>
Summary of Reactive Forms in Angular
✔ Built-in Validators: required
, minLength
, email
, pattern
, etc.
✔ Custom Validators: For advanced validation like strong passwords.
✔ Async Validators: For checking API data, like email availability.
Template Driven Forms
Template-driven Forms are used for small or simple forms, while Reactive forms are mostly used for complex forms. Template-driven forms use Two-ways binding to update the date model in the component as changes are made in the Template and vice versa. You can build any kind of form using Template- login form, contact form, and any business form. It uses built-in validators to manage the form input and user validation.
Key features of Template Driven approach
- Simple and easy to use: Template-driven forms are simple to implement, and most of the logic is handled in an HTML template, which makes the code clean and simple. In template-driven forms, Angular automatically manages form control and validation.
- Use ng-model for two-way binding: In template-driven form, Angular uses ng-model for two-way binding means data can flow in both directions, from the component to the form and from the form to the component.
- Automatic form management: In template-driven forms, Angular automatically manages form data like form control, form state, form validation, and form submission.
It used ng-directives for controlling the form.
- Built-in form validation: Angular has various built-in Validator methods for controlling the form. These validators can be applied using HTML attributes, and Angular automatically checks the input against them. Examples- requires, minLength, maxLength, min, max, disabled, required.
- Form state Tracking: Angular automatically tracks the state of each form and form control. Like when we make changes in the input field, update, delete, or enter any invalid data so all these actions are tracked by Angular automatically.
Working with Template-Driven Forms in Angular
Template-driven forms in Angular allow you to handle form validation and data binding directly in the template (.html
file). The best thing is that you don’t need to write much TypeScript code.
Steps to Create a Template-Driven Form in Angular
1️. Import FormsModule
Before using template-driven forms, import FormsModule
in your app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // Import FormsModule
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule], // Add FormsModule here
bootstrap: [AppComponent]
})
export class AppModule {}
2️. Create the Form in HTML
In your app.component.html, create a simple form using ngModel
:
<form #myForm="ngForm" (ngSubmit)="onSubmit()"><br> <!-- Name Input --><br> <label for="name">Name:</label><br> <input type="text" id="name" name="name" [(ngModel)]="user.name" required /><br><br> <!-- Email Input --><br> <label for="email">Email:</label><br> <input type="email" id="email" name="email" [(ngModel)]="user.email" required email /><br><br> <!-- Submit Button --><br> <button type="submit" [disabled]="myForm.invalid">Submit</button><br></form>
3️. Handle Form Submission in TypeScript
In app.component.ts, define the user
object and onSubmit()
method:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
user = { name: '', email: '' }; // Data model
onSubmit() {
console.log('Form Submitted!', this.user);
}
}
Form Validation in Template-Driven Forms
Angular automatically validates form fields using directives like required
, email
, minlength
, etc.
Example of error messages:
<input type="email" name="email" [(ngModel)]="user.email" required email #emailField="ngModel" />
<div *ngIf="emailField.invalid && emailField.touched">
<small *ngIf="emailField.errors?.required">Email is required.</small>
<small *ngIf="emailField.errors?.email">Invalid email format.</small>
</div>
Advantages of Template-Driven Forms
✅ Simple and easy to use
✅ Less code in TypeScript, more in HTML
✅ Best for small and simple forms
Disadvantages
❌ Not suitable for complex forms
❌ Difficult to scale and maintain
Conclusion: Reactive vs Template Driven– when to use
Templates driven and reactive forms these both approaches in Angular are very a powerful way to handle user input, but both have their benefits. Reactive forms are mostly used for complex designs, while template-driven forms are used for simple and small forms.
Both approaches are valid, and it’s your choice which one you choose according to your application needs and complexity. For complex forms, Reactive is better, while for simple forms, template driven is good.
Similar Blogs to Read
- What is Firebase and how to use it with Angular?
- React or Angular – Which is best for a beginner?
- Angular- 10 Minutes Installation and Deployment
- Why is Angular a Superheroic Web Framework?
- 5 Best Performance Tips for Angular Developers
- New Features of Angular 7 Not to Skip
- What are the 15 Most Important Features of Angular Not to Avoid?