Open In App

FormGroup and FormControl in Angular

Last Updated : 17 Sep, 2024
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

Handling forms is a common requirement in web applications, and Angular provides a robust solution through its Reactive Forms module. In this article, we will explore what FormGroup and FormControl are, how to use them, and best practices for building dynamic, reactive forms in Angular.

What are Reactive Forms in Angular?

Reactive Forms in Angular are a powerful approach to managing form inputs and validations by using a reactive and model-driven method. Unlike Template-Driven Forms, which rely on Angular's data binding, Reactive Forms use explicit and reactive programming principles, providing greater control over the form behaviour, validation, and state management.

What is FormControl in Angular?

FormControl is a class that tracks the value and validation status of an individual form input element. It provides methods and properties to control the input’s state, such as:

  • Value: The current value of the control.
  • Validation Status: Indicates whether the input is valid or invalid.
  • Touched/Untouched: Indicates whether the user has interacted with the input.
  • Dirty/Pristine: Indicates whether the input value has been changed.

Example:

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

@Component({
selector: 'app-simple-control',
template: `<input [formControl]="nameControl">`
})
export class SimpleControlComponent {
nameControl = new FormControl('');
}

In this example, nameControl is a FormControl instance that manages the value of the input field. The input field is bound to nameControl using Angular’s [formControl] directive.

What is FormGroup in Angular?

FormGroup is a class that tracks the value and validation status of a collection of FormControls. It is used to group related form controls into a cohesive unit, such as when building forms with multiple input fields. FormGroup allows you to manage multiple form controls together, making it easier to validate and handle form data as a group.

Example:

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

@Component({
selector: 'app-simple-form',
template: `
<form [formGroup]="profileForm">
<label>
First Name:
<input formControlName="firstName">
</label>
<label>
Last Name:
<input formControlName="lastName">
</label>
<button (click)="onSubmit()">Submit</button>
</form>
`
})
export class SimpleFormComponent {
profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl('')
});

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

In this example, profileForm is a FormGroup containing two FormControls: firstName and lastName. The form is managed as a unit, allowing for unified validation and value retrieval.

Setting Up Reactive Forms in Angular

Before you can use Reactive Forms in Angular, you need to import the ReactiveFormsModule from @angular/forms into your Angular module.

Step 1: Install Angular CLI and Create a New Project:

If you haven't already, install Angular CLI and create a new Angular project:

npm install -g @angular/cli
ng new my-angular-application
cd my-angular-application

Step 2: Generate a New Component

ng generate component register

Folder Structure

fgrg
Folder Structure

Dependencies

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

Step 3: Generate and Implement Register component:

HTML
<!-- src/app/register/register.component.html -->

<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
    <div>
        <label for="name">Name:</label>
        <input id="name" formControlName="name" />
        <div *ngIf="name?.invalid && (name?.dirty || name?.touched)" class="error">
            <div *ngIf="name?.errors?.['required']">Name is required.</div>
            <div *ngIf="name?.errors?.['minlength']">
                Name must be at least 3 characters long.
            </div>
        </div>
    </div>

    <div>
        <label for="email">Email:</label>
        <input id="email" formControlName="email" />
        <div *ngIf="email?.invalid && (email?.dirty || email?.touched)" class="error">
            <div *ngIf="email?.errors?.['required']">Email is required.</div>
            <div *ngIf="email?.errors?.['email']">Invalid email format.</div>
        </div>
    </div>

    <div>
        <label for="password">Password:</label>
        <input id="password" type="password" formControlName="password" />
        <div *ngIf="password?.invalid && (password?.dirty || password?.touched)" class="error">
            <div *ngIf="password?.errors?.['required']">Password is required.</div>
            <div *ngIf="password?.errors?.['minlength']">
                Password must be at least 6 characters long.
            </div>
        </div>
    </div>

    <button type="submit" [disabled]="registrationForm.invalid">Register</button>
</form>

<!-- Popup Modal -->
<div class="popup" *ngIf="isPopupVisible">
    <div class="popup-content">
        <h3>Registration Successful!</h3>
        <p>Your registration was submitted successfully.</p>
        <button (click)="closePopup()">Close</button>
    </div>
</div>
CSS
/* src/app/register/register.component.css */

form {
    max-width: 400px;
    margin: auto;
}

div {
    margin-bottom: 15px;
}

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

input {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
}

.error {
    color: red;
    font-size: 12px;
}

button {
    padding: 10px 15px;
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
}

button:disabled {
    background-color: #ccc;
    cursor: not-allowed;
}

/* Popup styling */
.popup {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
}

.popup-content {
    background: white;
    padding: 20px;
    border-radius: 8px;
    text-align: center;
}

.popup-content button {
    margin-top: 10px;
    padding: 8px 15px;
    background-color: #28a745;
    color: white;
    border: none;
    cursor: pointer;
}
JavaScript
// src/app/register/register.component.ts

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

@Component({
    selector: 'app-register',
    standalone: true,
    imports: [CommonModule, ReactiveFormsModule],
    templateUrl: './register.component.html',
    styleUrls: ['./register.component.css'],
})
export class RegisterComponent {
    // Define the FormGroup and FormControls
    registrationForm = 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),
        ]),
    });

    // Property to control the visibility of the popup
    isPopupVisible = false;

    // Getter methods for form controls
    get name() {
        return this.registrationForm.get('name');
    }
    get email() {
        return this.registrationForm.get('email');
    }
    get password() {
        return this.registrationForm.get('password');
    }

    // Method to handle form submission
    onSubmit() {
        if (this.registrationForm.valid) {
            this.isPopupVisible = true; // Show the popup when the form is valid
            console.log('Form Submitted', this.registrationForm.value);
        } else {
            console.log('Form is invalid');
        }
    }

    // Method to close the popup
    closePopup() {
        this.isPopupVisible = false;
    }
}

Step 4: Add the register component into the main application

HTML
<!-- src/app/app.component.html -->
<app-register></app-register>
JavaScript
// src/app/app.component.ts

import { Component } from '@angular/core';
import { RegisterComponent } from './register/register.component';

@Component({
    selector: 'app-root',
    standalone: true,
    imports: [RegisterComponent],
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    title = 'Reactive Forms in Angular';
}


To start the application run the following command.

ng serve --open

Output


Next Article
Article Tags :

Similar Reads