Open In App

How To Use Reactive Forms in Angular?

Last Updated : 13 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In Angular, the forms are an important part of handling user input and validation. Reactive Forms offers a model-driven approach that provides greater control and flexibility by managing form controls, validation, and data binding directly within the component class.

Core Components

  1. FormGroup: Represents a collection of FormControl instances. It is used to group related form controls, such as those in a form.
  2. FormControl: Represents a single form control. It manages the value and validation status of an individual input field.
  3. FormArray: Manages an array of FormControl or FormGroup instances, allowing for dynamic and repeatable form controls.
  4. Validators: Provides built-in validation functions, such as required, minLength, email, and min, which can be used to validate form controls.

Approach

  • Import ReactiveFormsModule in the AppModule.
  • We will create FormGroup and FormControl instances within the component's ngOnInit method, defining form controls and their validations.
  • We then bind the form model to the template using [formGroup] and formControlName and handle form submission with a method that processes the form data.

Steps to Use Reactive Forms in Angular

Step 1: Install Angular CLI

If you haven’t installed Angular CLI yet, install it using the following command

npm install -g @angular/cli

Step 2: Create a New Angular Project

ng new form-app --no-standalone
cd form-app

Step 3: Create Standalone Component

Create a standalone component. You can generate a standalone component using the Angular CLI:

ng generate component user-form

Dependencies

 "dependencies": {
"@angular/animations": "^18.1.4",
"@angular/common": "^18.1.4",
"@angular/compiler": "^18.1.4",
"@angular/core": "^18.1.4",
"@angular/forms": "^18.1.4",
"@angular/platform-browser": "^18.1.4",
"@angular/platform-browser-dynamic": "^18.1.4",
"@angular/router": "^18.1.4",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.10"
}

Project Structure

PS
Folder Structure

Example: In this example, we are using Reactive Forms in Angular to create a user form with fields for name, email, and age. The form includes validation rules and displays error messages if the inputs are invalid. After submission, if the form is valid, the form data is shown centered below the submit button. This approach uses Angular’s form controls and validation mechanisms to handle user inputs and feedback effectively.

HTML
<!-- src/app/user-form/user-form.component.html -->

<h1 class="header">GeeksforGeeks</h1>
<h3>Reactive Forms in Angular</h3>

<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
    <!-- Existing Fields -->
    <label for="name">Name:</label>
    <input id="name" type="text" formControlName="name">
    <div *ngIf="userForm.get('name')!.invalid && userForm.get('name')!.touched">
        Name is required and must be at least 3 characters long.
    </div>

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

    <label for="age">Age:</label>
    <input id="age" type="number" formControlName="age">
    <div *ngIf="userForm.get('age')!.invalid && userForm.get('age')!.touched">
        Age is required and must be 18 or older.
    </div>

    <!-- New Fields -->
    <label for="phoneNumber">Phone Number:</label>
    <input id="phoneNumber" type="text" formControlName="phoneNumber">
    <div *ngIf="userForm.get('phoneNumber')!.invalid &&
                userForm.get('phoneNumber')!.touched">
        Phone number is required and must be 10 digits.
    </div>

    <label for="address">Address:</label>
    <input id="address" type="text" formControlName="address">
    <div *ngIf="userForm.get('address')!.invalid && userForm.get('address')!.touched">
        Address is required.
    </div>

    <label for="country">Country:</label>
    <select id="country" formControlName="country">
        <option value="" disabled>Select your country</option>
        <option *ngFor="let country of countries" [value]="country">{{ country }}</option>
    </select>
    <div *ngIf="userForm.get('country')!.invalid && userForm.get('country')!.touched">
        Country is required.
    </div>

    <label for="dateOfBirth">Date of Birth:</label>
    <input id="dateOfBirth" type="date" formControlName="dateOfBirth">
    <div *ngIf="userForm.get('dateOfBirth')!.invalid &&
                userForm.get('dateOfBirth')!.touched">
        Date of Birth is required.
    </div>

    <label for="password">Password:</label>
    <input id="password" type="password" formControlName="password">
    <div *ngIf="userForm.get('password')!.invalid && userForm.get('password')!.touched">
        Password is required and must be at least 6 characters long.
    </div>

    <label for="confirmPassword">Confirm Password:</label>
    <input id="confirmPassword" type="password" formControlName="confirmPassword">
    <div *ngIf="userForm.get('confirmPassword')!.invalid &&
                userForm.get('confirmPassword')!.touched">
        Confirm Password is required.
    </div>
    <div *ngIf="userForm.errors?.['passwordsMismatch']">
        Passwords do not match.
    </div>

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

<div *ngIf="userForm.valid" class="form-data">
    <pre>{{ userForm.value | json }}</pre>
</div>
HTML
<!--// src/app/app.component.html-->

<app-user-form></app-user-form>
CSS
/* src/app/user-form/user-form.component.css */

form {
	max-width: 400px;
	margin: 20px auto;
	padding: 20px;
	border: 1px solid #ccc;
	border-radius: 5px;
}

label {
	display: block;
	margin-bottom: 5px;
}

input,
select {
	width: 100%;
	padding: 8px;
	margin-bottom: 10px;
	border: 1px solid #ccc;
	border-radius: 4px;
}

div {
	color: red;
	margin-bottom: 10px;
}

button {
	width: 100%;
	padding: 10px;
	background-color: #007bff;
	color: white;
	border: none;
	border-radius: 5px;
	cursor: pointer;
}

button:disabled {
	background-color: #ccc;
}

.header {
	color: green;
	text-align: center;
}

h3 {
	text-align: center;
}

.form-data {
	text-align: center;
	margin-top: 20px;
}
JavaScript
// src/app/app.module.ts

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

@NgModule({
    declarations: [
        AppComponent,
        UserFormComponent
    ],
    imports: [
        BrowserModule,
        ReactiveFormsModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
JavaScript
// src/app/user-form/user-form-component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { UserFormComponent } from './user-form.component';

describe('UserFormComponent', () => {
    let component: UserFormComponent;
    let fixture: ComponentFixture<UserFormComponent>;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [UserFormComponent]
        });
        fixture = TestBed.createComponent(UserFormComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });
});
JavaScript
// src/app/user-form/user-form.component.ts

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

@Component({
    selector: 'app-user-form',
    templateUrl: './user-form.component.html',
    styleUrls: ['./user-form.component.css']
})
export class UserFormComponent implements OnInit {
    userForm!: FormGroup;
    countries = ['United States', 'India', 'United Kingdom', 'Australia'];

    ngOnInit() {
        this.userForm = 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)]),
            phoneNumber: new FormControl('', [Validators.required,
            Validators.pattern(/^\d{10}$/)]), 
            // Example pattern for a 10-digit phone number
            address: new FormControl('', [Validators.required]),
            country: new FormControl('', [Validators.required]),
            dateOfBirth: new FormControl('', [Validators.required]),
            password: new FormControl('', [Validators.required, Validators.minLength(6)]),
            confirmPassword: new FormControl('', [Validators.required])
        }, { validators: this.passwordsMatch() });
    }

    passwordsMatch(): ValidatorFn {
        return (group: AbstractControl): { [key: string]: any } | null => {
            const password = group.get('password')?.value;
            const confirmPassword = group.get('confirmPassword')?.value;
            return password === confirmPassword ? null : { passwordsMismatch: true };
        };
    }

    onSubmit() {
        if (this.userForm.valid) {
            console.log('Form Submitted!', this.userForm.value);
        } else {
            console.log('Form not valid');
        }
    }
}
JavaScript
// src/app/app.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    title = 'reactive-forms-example';
}


Steps to run this Project

ng serve --open

Output


Next Article
Article Tags :

Similar Reads