Table of contents
1.
Introduction
2.
Core Components
3.
Understanding Reactive Forms: Approach
3.1.
Key Features of Reactive Forms:
3.2.
Advantages
4.
Steps to Use Reactive Forms in Angular
4.1.
Step 1: Import ReactiveFormsModule
4.2.
Step 2: Define FormGroup and FormControl in the Component
4.3.
Step 3: Create the Template
5.
Reactive Form Control & Sync View  
5.1.
1. FormControl 
5.1.1.
Example:  
5.2.
2. FormGroup  
5.2.1.
Example
5.3.
3. FormArray
5.3.1.
Example:
5.4.
Syncing with the View  
5.4.1.
Example:
5.4.2.
1. Define Form Controls in the Component Class:  
6.
Project Structure
7.
Steps to Run This Project
7.1.
Step 1: Install Angular CLI (if not already installed)
7.2.
Step 2: Create a New Angular Project
7.3.
Step 3: Add Reactive Forms Module
7.4.
Step 4: Add the Form Logic and Template
7.5.
Step 5: Run the Application
8.
Dynamic Validations in Reactive Forms  
8.1.
1. Adding Validations to Form Controls  
8.2.
2. Displaying Validation Errors in the Template  
8.3.
3. Adding Custom Validators  
8.4.
4. Dynamic Validations Based on User Input  
8.5.
5. Cross-Field Validations  
9.
Template Driven Forms Vs. Reactive Forms
10.
Frequently Asked Questions
10.1.
What are Reactive Forms in Angular?
10.2.
How are Reactive Forms different from Template-Driven Forms?
10.3.
What are some key components of Reactive Forms in Angular?
11.
Conclusion
Last Updated: Jan 3, 2025
Medium

Reactive Forms in Angular

Author Rahul Singh
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Reactive Forms in Angular are a powerful tool for building and managing forms in modern web applications. They allow developers to create forms programmatically using TypeScript, making the form structure easier to control and highly adaptable for complex use cases. Unlike template-driven forms, Reactive Forms use a model-driven approach, meaning that the form and its validation logic are tightly connected to the application's data model. This provides a robust way to handle dynamic validation, user inputs, and error messages.

Reactive Forms in Angular

In this article, we will discuss how to build reactive forms, understand their core components, and see how to implement them in an Angular project. 

Core Components

Reactive forms in Angular are based on a few core components that help manage form inputs effectively. These components include:

  1. FormGroup: A collection of FormControl instances. It represents the entire form and manages its values and validations.
     
  2. FormControl: Represents an individual input field in the form, such as text boxes or checkboxes.
     
  3. FormArray: A collection of FormControl or FormGroup instances, which allows you to manage an array of inputs dynamically.
     
  4. Validators: Functions that enforce validation rules on form controls, such as required, minlength, or pattern.
     

These components work together to provide a more flexible way of handling forms, giving developers the ability to dynamically change form values, validations, and reactions based on user input.

Understanding Reactive Forms: Approach

The reactive form approach is different from the template-driven form approach in Angular. In reactive forms, the model is created in the component class, and the form is updated by the component itself, rather than in the HTML template.

Key Features of Reactive Forms:

  • Explicit management of the form model in the component class.
     
  • No reliance on the template to define form control properties.
     
  • Easier to unit-test due to explicit form models in the component class.
     
  • Dynamic form creation, where form controls can be added or removed based on user input.

Advantages

  • Better scalability and flexibility for complex forms.
     
  • Form control and validation logic can be entirely encapsulated in the component class.

Steps to Use Reactive Forms in Angular

To start using reactive forms, you need to follow these steps:

Step 1: Import ReactiveFormsModule

In order to work with reactive forms, you need to import ReactiveFormsModule from @angular/forms in your Angular module.

import { ReactiveFormsModule } from '@angular/forms';


@NgModule({
  imports: [
    ReactiveFormsModule
  ]
})
export class AppModule { }

Step 2: Define FormGroup and FormControl in the Component

Next, you will define the FormGroup and FormControl in your component. This is where you will set up the form controls and validations.

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 {
  // Defining the form group with form controls and validations
  userForm = new FormGroup({
    name: new FormControl('', [Validators.required, Validators.minLength(3)]),
    email: new FormControl('', [Validators.required, Validators.email]),
  });


  // Method to handle form submission
  onSubmit() {
    console.log(this.userForm.value);
  }
}

Step 3: Create the Template

In the template, you need to bind the form controls using formGroup and formControlName.

<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Name</label>
    <input id="name" formControlName="name">
    <div *ngIf="userForm.get('name').invalid && userForm.get('name').touched">
      Name is required and should be at least 3 characters.
    </div>
  </div>


  <div>
    <label for="email">Email</label>
    <input id="email" formControlName="email">
    <div *ngIf="userForm.get('email').invalid && userForm.get('email').touched">
      Enter a valid email address.
    </div>
  </div>


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


Explanation:

  • The formGroup directive binds the form model to the HTML form.
     
  • The formControlName directive connects the form control to a specific input field.
     
  • The onSubmit() method logs the form values to the console when the user submits the form.

Reactive Form Control & Sync View  

Reactive forms in Angular are built using three main building blocks: FormControl, FormGroup, & FormArray. These classes help you create & manage form controls programmatically. Let’s understand each of these & how they sync with the view.  

1. FormControl 

A `FormControl` represents a single form element, like an input field, checkbox, or dropdown. It tracks the value, validation status, & interaction state (e.g., touched, untouched) of the control.  

Example:  

import { FormControl } from '@angular/forms';
// Create a FormControl for an input field
username = new FormControl('');


In this example, `username` is a `FormControl` that represents an input field. The empty string `''` is the initial value of the control.  

2. FormGroup  

A `FormGroup` is a collection of `FormControl` instances. It helps you manage multiple form controls together & track their collective state.  

Example

import { FormGroup, FormControl } from '@angular/forms';
// Create a FormGroup with multiple FormControl instances
loginForm = new FormGroup({
  username: new FormControl(''),
  password: new FormControl('')
});


Here, `loginForm` is a `FormGroup` containing two `FormControl` instances: `username` & `password`.  

3. FormArray

A `FormArray` is used to manage a dynamic list of form controls. It’s useful when you need to add or remove form controls dynamically.  

Example:

import { FormArray, FormControl } from '@angular/forms';
// Create a FormArray with multiple FormControl instances
hobbies = new FormArray([
  new FormControl('Reading'),
  new FormControl('Coding')
]);

 
In this example, `hobbies` is a `FormArray` containing two `FormControl` instances.  

Syncing with the View  

To sync the form controls with the view, Angular provides directives like `formControl`, `formGroup`, & `formArrayName`. These directives bind the form controls defined in the component class to the HTML template.  

Example:

<form [formGroup]="loginForm">
  <label for="username">Username:</label>
  <input id="username" formControlName="username">
<label for="password">Password:</label>
  <input id="password" formControlName="password">
</form>


Here, the `formGroup` directive binds the `loginForm` group to the `<form>` element, & `formControlName` binds individual controls to their respective input fields.  

Let’s understand the code Step-by-Step:  

1. Define Form Controls in the Component Class:  

   import { Component } from '@angular/core';
   import { FormGroup, FormControl } from '@angular/forms';
  @Component({
     selector: 'app-login',
     templateUrl: './login.component.html'
   })
   export class LoginComponent {
     loginForm = new FormGroup({
       username: new FormControl(''),
       password: new FormControl('')
     });
   }


2. Bind Form Controls to the Template:  

   <form [formGroup]="loginForm">
     <label for="username">Username:</label>
     <input id="username" formControlName="username">
     <label for="password">Password:</label>
     <input id="password" formControlName="password">
   </form>


3. Access Form Values in the Component:  

You can access the form values using the `value` property of the `FormGroup`.  

onSubmit() {
     console.log(this.loginForm.value);
   }


This is how reactive forms work in Angular. The form controls are defined programmatically in the component class & synced with the view using Angular directives.  

Project Structure

Here’s how a typical Angular project structure would look when implementing reactive forms:

src/
  app/
    app.component.ts   <-- Component class for form logic
    app.component.html <-- Template for form rendering
    app.component.css  <-- Styles for the form
    app.module.ts      <-- Angular module with ReactiveFormsModule

 

  • app.component.ts: Contains the form logic such as form control definition, validation, and form submission handling.
     
  • app.component.html: Contains the form HTML and form control bindings.
     
  • app.component.css: Styles for the form elements.
     
  • app.module.ts: The module where ReactiveFormsModule is imported and the AppComponent is declared.

Steps to Run This Project

To run a basic Angular project using reactive forms, follow these steps:

Step 1: Install Angular CLI (if not already installed)

Run the following command to install Angular CLI globally:

npm install -g @angular/cli

Step 2: Create a New Angular Project

Create a new Angular project by running:

ng new reactive-forms-demo


Navigate into your project directory:

cd reactive-forms-demo

Step 3: Add Reactive Forms Module

Add ReactiveFormsModule to your application by modifying the app.module.ts file (as shown earlier).

Step 4: Add the Form Logic and Template

Update the app.component.ts and app.component.html files with the form code provided earlier.

Step 5: Run the Application

Start the development server by running the following command:

ng serve


Once the server is running, open http://localhost:4200/ in your browser to see the form in action.

Dynamic Validations in Reactive Forms  

One of the most powerful features of reactive forms is the ability to add **dynamic validations**. Unlike template-driven forms, where validations are static & defined in the template, reactive forms allow you to define & update validations programmatically. This is especially useful for forms with conditional logic or complex validation requirements.  

1. Adding Validations to Form Controls  

Angular provides built-in validators like `Validators.required`, `Validators.minLength`, `Validators.maxLength`, & `Validators.pattern`. You can apply these validators when creating a `FormControl`.  

Example:

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

// Create a FormGroup with validations
loginForm = new FormGroup({
  username: new FormControl('', [Validators.required, Validators.minLength(3)]),
  password: new FormControl('', [Validators.required, Validators.minLength(6)])
});


In this example:  

  • The `username` field is required & must have at least 3 characters.  
     
  • The `password` field is required & must have at least 6 characters.  

2. Displaying Validation Errors in the Template  

To show validation errors, you can check the status of the form controls using properties like `invalid`, `touched`, & `errors`.  

Example:

<form [formGroup]="loginForm">
  <label for="username">Username:</label>
  <input id="username" formControlName="username">
  <div *ngIf="loginForm.get('username').invalid && loginForm.get('username').touched">
    <p *ngIf="loginForm.get('username').errors?.required">Username is required.</p>
    <p *ngIf="loginForm.get('username').errors?.minlength">Username must be at least 3 characters long.</p>
  </div>
 <label for="password">Password:</label>
  <input id="password" formControlName="password">
  <div *ngIf="loginForm.get('password').invalid && loginForm.get('password').touched">
    <p *ngIf="loginForm.get('password').errors?.required">Password is required.</p>
    <p *ngIf="loginForm.get('password').errors?.minlength">Password must be at least 6 characters long.</p>
  </div>
</form>


Here, error messages are displayed only if the control is invalid & has been touched by the user.  

3. Adding Custom Validators  

Sometimes, built-in validators are not enough. You can create custom validators to handle specific validation logic.  

Example:

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

// Custom validator to check if the password contains a special character
function passwordValidator(control: AbstractControl): ValidationErrors | null {
  const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(control.value);
  return hasSpecialChar ? null : { noSpecialChar: true };
}

// Apply the custom validator to the password field
loginForm = new FormGroup({
  username: new FormControl('', [Validators.required, Validators.minLength(3)]),
  password: new FormControl('', [Validators.required, Validators.minLength(6), passwordValidator])
});


In the template, you can display the custom validation error like this:  

<div *ngIf="loginForm.get('password').invalid && loginForm.get('password').touched">
  <p *ngIf="loginForm.get('password').errors?.noSpecialChar">Password must contain at least one special character.</p>
</div>

4. Dynamic Validations Based on User Input  

Reactive forms allow you to add or remove validations dynamically based on user input or other conditions.  

Example: 

// Add a checkbox to toggle password validation
loginForm = new FormGroup({
  username: new FormControl('', [Validators.required, Validators.minLength(3)]),
  password: new FormControl('', [Validators.required, Validators.minLength(6)]),
  enableSpecialChar: new FormControl(false)
});


// Listen for changes in the checkbox & update validations
this.loginForm.get('enableSpecialChar').valueChanges.subscribe((value) => {
  const passwordControl = this.loginForm.get('password');
  if (value) {
    passwordControl.setValidators([Validators.required, Validators.minLength(6), passwordValidator]);
  } else {
    passwordControl.setValidators([Validators.required, Validators.minLength(6)]);
  }
  passwordControl.updateValueAndValidity();
}); 


In this example:  

  • A checkbox (`enableSpecialChar`) is added to the form.  
     
  • When the checkbox is checked, the custom `passwordValidator` is added to the `password` field.  
     
  • When the checkbox is unchecked, the custom validator is removed.  

5. Cross-Field Validations  

Sometimes, you need to validate one field based on the value of another field. This is called cross-field validation.  

Example:  

// Custom validator to check if the password & confirm password match
function confirmPasswordValidator(control: AbstractControl): ValidationErrors | null {
  const password = control.get('password').value;
  const confirmPassword = control.get('confirmPassword').value;
  return password === confirmPassword ? null : { mismatch: true };
}
// Apply the custom validator to the form group
signupForm = new FormGroup({
  username: new FormControl('', [Validators.required, Validators.minLength(3)]),
  password: new FormControl('', [Validators.required, Validators.minLength(6)]),
  confirmPassword: new FormControl('', [Validators.required])
}, { validators: confirmPasswordValidator });


In the template, you can display the cross-field validation error like this:  

<div *ngIf="signupForm.errors?.mismatch && signupForm.get('confirmPassword').touched">
  <p>Passwords do not match.</p>
</div>


This is how dynamic validations work in reactive forms. You can add, remove, or update validations programmatically based on user input or other conditions.  

Template Driven Forms Vs. Reactive Forms

ParametersTemplate-Driven FormsReactive Forms
ControlControls are defined in the HTML template.Controls are defined programmatically in the component class.
Form ModelThe form model is implicit, created by Angular.The form model is explicit, created by the developer.
Data FlowTwo-way data binding using ngModel.One-way data binding with explicit control over data flow.
ValidationValidation is done using directives in the template.Validation is done programmatically in the component class.
Dynamic BehaviorLess flexible for dynamic form controls.Highly flexible for dynamic form controls & validations.
Use CaseBest for simple forms with minimal logic.Best for complex forms with dynamic behavior.

Frequently Asked Questions

What are Reactive Forms in Angular?

Reactive forms in Angular provide a way to manage form input and validation programmatically in the component class. They give developers more control over form behavior than template-driven forms.

How are Reactive Forms different from Template-Driven Forms?

In reactive forms, the form model is explicitly defined in the component class using FormGroup and FormControl. In template-driven forms, the model is managed directly in the HTML template, with less control over form state and validation.

What are some key components of Reactive Forms in Angular?

The core components of reactive forms include FormGroup, FormControl, FormArray, and Validators. These components help manage form inputs, control their values, and apply validations.

Conclusion

In this article, we covered the basics of reactive forms in Angular, including the core components and the steps to create and manage forms. We learned how to set up a form, define form controls, and apply validations in a structured way. Reactive forms are a powerful tool for handling complex forms and validations in Angular applications, making them an essential skill for modern web developers.

You can also check out our other blogs on Code360.

Live masterclass