Introduction

In this article, we are going to discuss forms and their types in Angular with step-by-step practical implementation.

Prerequisites

What is Angular?

Angular is a popular open-source JavaScript framework for building web applications. It was developed by Google and is currently maintained by the Angular Team at Google. Angular allows developers to create dynamic, single-page applications (SPAs) and provides a structured approach to building complex web applications.

Forms in Angular

In Angular, Forms provides a set of features that help us handle and manage user input in a structured and efficient manner. Forms are the main part of web applications that allow users to interact with the application and submit data to the application.

Types of Forms in Angular

Angular provides the following two types of forms:

1. Template-Driven Forms

Template-driven forms are the basic forms that are suitable for the development of a limited number of fields and with simpler validation. In this form, each field is represented as a property in the component class. You Need to import FormsModule from the ‘@angular/forms’ package.

Following are the key concepts related to validation objects and properties that we used while creating the template-driven forms in Angular.

2. Reactive Forms

Reactive forms, or model-driven forms, are the types of forms in Angular that are suitable for creating a large form with different form fields and complex validation. In the reactive form, each form field is considered a Form Control, and a set of form controls is called a Form Group.The validation rules are defined in the component with the Validators object, and validation messages can be displayed in the template with the help of the validation property. ReactiveFormModule needs to be imported from the ‘@angular/forms’ package.

Following are the key concepts related to validation objects and properties that we used while creating the reactive forms in Angular.

Practical Implementation

Step 1 - Create a new Angular application.

ng new angular-forms

Step 2 - Install the bootstrap module with the help of the following command:

npm install bootstrap

Configure bootstrap in an Angular JSON file.

 "styles": [
              "src/styles.css",
              "./node_modules/bootstrap/dist/css/bootstrap.min.css"
            ],
            "scripts": [
              "./node_modules/bootstrap/dist/js/bootstrap.min.js"
            ]

Step 3 - Next, add two components to the newly created project.

ng g c components/template-driven-form

template-driven-form.component.html

<div class="container">
    <h2 class="heading">Template Driven Form</h2>
    <form #userForm="ngForm" (ngSubmit)="submitForm(userForm)">
   
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" id="name" name="name" [(ngModel)]="userDetails.name" required>
        <div *ngIf="userForm.controls.name?.touched && userForm.controls.name?.invalid" class="text-danger">
          Name is required.
        </div>
      </div>
      
      <div class="form-group">
        <label for="email">Email</label>
        <input type="email" class="form-control" id="email" name="email" [(ngModel)]="userDetails.email" required email>
        <div *ngIf="userForm.controls.email?.touched && userForm.controls.email?.invalid" class="text-danger">
          Please enter a valid email address.
        </div>
      </div>
  
      <div class="form-group">
        <label for="address">Address</label>
        <input type="text" class="form-control" id="address" name="address" [(ngModel)]="userDetails.address" required>
        <div *ngIf="userForm.controls.address?.touched && userForm.controls.address?.invalid" class="text-danger">
          Address is required.
        </div>
      </div>
  
      <div class="form-group">
        <label for="mobile">Mobile Number</label>
        <input type="tel" class="form-control" id="mobile" name="mobile" [(ngModel)]="userDetails.mobile" required pattern="[0-9]{10}">
        <div *ngIf="userForm.controls.mobile?.touched && userForm.controls.mobile?.invalid" class="text-danger">
          Please enter a valid mobile number.
        </div>
      </div>
  
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" name="age" [(ngModel)]="userDetails.age" required min="20" max="60">
        <div *ngIf="userForm.controls.age?.touched && userForm.controls.age?.invalid" class="text-danger">
          Please enter a valid age.
        </div>
      </div>
  
      <div class="form-group">
        <label for="gender">Gender</label>
        <select class="form-control" id="gender" name="gender" [(ngModel)]="userDetails.gender" required>
          <option value="" disabled>Select Gender</option>
          <option value="male">Male</option>
          <option value="female">Female</option>
          <option value="other">Other</option>
        </select>
        <div *ngIf="userForm.controls.gender?.touched && userForm.controls.gender?.invalid" class="text-danger">
          Please select a gender.
        </div>
      </div>

      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>

template-driven-form.component.ts

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

@Component({
  selector: 'app-template-driven-form',
  templateUrl: './template-driven-form.component.html',
  styleUrls: ['./template-driven-form.component.css']
})
export class TemplateDrivenFormComponent {
  userDetails = {
    name: '',
    email: '',
    address: '',
    mobile: '',
    age: null,
    gender: ''
  };

  submitForm(form: any): void {
    if (form.valid) {
      console.log('Form data:', this.userDetails);
    }
  }
}

In this example, #userForm=”ngForm” creates a form reference that you can use to access the form controls. The [(ngModel)] directive establishes a two-way data binding between the input elements and properties of the user object in the component.

The validation directives (required and email) are applied to the form controls, and error messages are displayed conditionally based on the control’s state.

Template Data Driven

Next, create a reactive form, as shown below.

Create a new component using the following command.

ng g c components/reactive-form

reactive-form.component.html

<div class="container">
    <h2 class="heading">Reactive Form</h2>
    <form [formGroup]="userForm" (ngSubmit)="submitForm()">

        <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" id="name" formControlName="name">
        <div *ngIf="userForm?.get('name')?.invalid && userForm?.get('name')?.touched" class="text-danger">
          Name is required.
        </div>
      </div>
  
      <div class="form-group">
        <label for="email">Email</label>
        <input type="email" class="form-control" id="email" formControlName="email">
        <div *ngIf="userForm?.get('email')?.invalid && userForm?.get('email')?.touched" class="text-danger">
          Please enter a valid email.
        </div>
      </div>
  
      <div class="form-group">
        <label for="address">Address</label>
        <input type="text" class="form-control" id="address" formControlName="address">
        <div *ngIf="userForm?.get('address')?.invalid && userForm?.get('address')?.touched" class="text-danger">
          Address is required.
        </div>
      </div>
  
      <div class="form-group">
        <label for="mobile">Mobile Number</label>
        <input type="tel" class="form-control" id="mobile" formControlName="mobile">
        <div *ngIf="userForm?.get('mobile')?.invalid && userForm?.get('mobile')?.touched" class="text-danger">
          Please enter a valid mobile number.
        </div>
      </div>
  
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" formControlName="age">
        <div *ngIf="userForm?.get('age')?.invalid && userForm?.get('age')?.touched" class="text-danger">
          Please enter a valid age (between 1 and 120).
        </div>
      </div>
  
      <div class="form-group">
        <label for="gender">Gender</label>
        <select class="form-control" id="gender" formControlName="gender">
          <option value="" disabled>Select Gender</option>
          <option value="male">Male</option>
          <option value="female">Female</option>
          <option value="other">Other</option>
        </select>
        <div *ngIf="userForm?.get('gender')?.invalid && userForm?.get('gender')?.touched" class="text-danger">
          Please select a gender.
        </div>
      </div>
  
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>

reactive-form.component.ts

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

@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html',
  styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent {
  userForm: any;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.userForm = this.formBuilder.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
      address: ['', Validators.required],
      mobile: ['', [Validators.required, Validators.pattern('[0-9]{10}')]],
      age: ['', [Validators.required, Validators.min(20), Validators.max(50)]],
      gender: ['', Validators.required]
    });
  }

  submitForm(): void {
    if (this.userForm?.valid) {
      console.log('Form data:', this.userForm.value);
    }
  }
}

Angular Form

Conclusion

In this article, we discussed the basics of forms, which are available in angular, and their different types with step-by-step implantation with different validators and their properties.