Form validation is a crucial aspect of any web application to ensure that the data entered by users is correct and meets the required criteria. Angular provides robust support for form validation, both for template-driven and reactive forms. In this section, we will cover the following topics:
- Introduction to Form Validation
- Built-in Validators
- Custom Validators
- Displaying Validation Messages
- Practical Exercises
- Introduction to Form Validation
Form validation in Angular can be achieved using two approaches:
- Template-driven forms: Validation is defined in the template using directives.
- Reactive forms: Validation is defined in the component class using form control objects.
- Built-in Validators
Angular provides several built-in validators that can be used to validate form controls. These include:
- Required: Ensures the field is not empty.
- MinLength: Ensures the field has a minimum length.
- MaxLength: Ensures the field does not exceed a maximum length.
- Pattern: Ensures the field matches a specific regex pattern.
- Email: Ensures the field contains a valid email address.
Example: Using Built-in Validators in Template-driven Forms
<form #userForm="ngForm"> <div> <label for="name">Name:</label> <input type="text" id="name" name="name" ngModel required minlength="3"> <div *ngIf="userForm.controls.name?.invalid && userForm.controls.name?.touched"> <small *ngIf="userForm.controls.name?.errors?.required">Name is required.</small> <small *ngIf="userForm.controls.name?.errors?.minlength">Name must be at least 3 characters long.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form>
Example: Using Built-in Validators in Reactive Forms
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-user-form', template: ` <form [formGroup]="userForm" (ngSubmit)="onSubmit()"> <div> <label for="name">Name:</label> <input type="text" id="name" formControlName="name"> <div *ngIf="userForm.controls.name.invalid && userForm.controls.name.touched"> <small *ngIf="userForm.controls.name.errors.required">Name is required.</small> <small *ngIf="userForm.controls.name.errors.minlength">Name must be at least 3 characters long.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form> ` }) export class UserFormComponent { userForm: FormGroup; constructor(private fb: FormBuilder) { this.userForm = this.fb.group({ name: ['', [Validators.required, Validators.minLength(3)]] }); } onSubmit() { if (this.userForm.valid) { console.log(this.userForm.value); } } }
- Custom Validators
Sometimes, built-in validators are not enough, and you need to create custom validators to meet specific requirements.
Example: Creating a Custom Validator
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const forbidden = nameRe.test(control.value); return forbidden ? { forbiddenName: { value: control.value } } : null; }; }
Using the Custom Validator in a Reactive Form
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { forbiddenNameValidator } from './forbidden-name.validator'; @Component({ selector: 'app-user-form', template: ` <form [formGroup]="userForm" (ngSubmit)="onSubmit()"> <div> <label for="name">Name:</label> <input type="text" id="name" formControlName="name"> <div *ngIf="userForm.controls.name.invalid && userForm.controls.name.touched"> <small *ngIf="userForm.controls.name.errors.required">Name is required.</small> <small *ngIf="userForm.controls.name.errors.forbiddenName">Name is forbidden.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form> ` }) export class UserFormComponent { userForm: FormGroup; constructor(private fb: FormBuilder) { this.userForm = this.fb.group({ name: ['', [Validators.required, forbiddenNameValidator(/admin/i)]] }); } onSubmit() { if (this.userForm.valid) { console.log(this.userForm.value); } } }
- Displaying Validation Messages
Displaying validation messages helps users understand what they need to correct in the form. This can be done using Angular's conditional rendering with *ngIf
.
Example: Displaying Validation Messages
<form [formGroup]="userForm" (ngSubmit)="onSubmit()"> <div> <label for="email">Email:</label> <input type="email" id="email" formControlName="email"> <div *ngIf="userForm.controls.email.invalid && userForm.controls.email.touched"> <small *ngIf="userForm.controls.email.errors.required">Email is required.</small> <small *ngIf="userForm.controls.email.errors.email">Invalid email address.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form>
- Practical Exercises
Exercise 1: Template-driven Form Validation
Create a template-driven form with the following fields:
- Username (required, minimum length 5)
- Password (required, minimum length 8)
- Email (required, valid email format)
Solution
<form #userForm="ngForm"> <div> <label for="username">Username:</label> <input type="text" id="username" name="username" ngModel required minlength="5"> <div *ngIf="userForm.controls.username?.invalid && userForm.controls.username?.touched"> <small *ngIf="userForm.controls.username?.errors?.required">Username is required.</small> <small *ngIf="userForm.controls.username?.errors?.minlength">Username must be at least 5 characters long.</small> </div> </div> <div> <label for="password">Password:</label> <input type="password" id="password" name="password" ngModel required minlength="8"> <div *ngIf="userForm.controls.password?.invalid && userForm.controls.password?.touched"> <small *ngIf="userForm.controls.password?.errors?.required">Password is required.</small> <small *ngIf="userForm.controls.password?.errors?.minlength">Password must be at least 8 characters long.</small> </div> </div> <div> <label for="email">Email:</label> <input type="email" id="email" name="email" ngModel required email> <div *ngIf="userForm.controls.email?.invalid && userForm.controls.email?.touched"> <small *ngIf="userForm.controls.email?.errors?.required">Email is required.</small> <small *ngIf="userForm.controls.email?.errors?.email">Invalid email address.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form>
Exercise 2: Reactive Form Validation
Create a reactive form with the following fields:
- First Name (required)
- Last Name (required)
- Age (required, must be a number between 18 and 65)
Solution
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-user-form', template: ` <form [formGroup]="userForm" (ngSubmit)="onSubmit()"> <div> <label for="firstName">First Name:</label> <input type="text" id="firstName" formControlName="firstName"> <div *ngIf="userForm.controls.firstName.invalid && userForm.controls.firstName.touched"> <small *ngIf="userForm.controls.firstName.errors.required">First Name is required.</small> </div> </div> <div> <label for="lastName">Last Name:</label> <input type="text" id="lastName" formControlName="lastName"> <div *ngIf="userForm.controls.lastName.invalid && userForm.controls.lastName.touched"> <small *ngIf="userForm.controls.lastName.errors.required">Last Name is required.</small> </div> </div> <div> <label for="age">Age:</label> <input type="number" id="age" formControlName="age"> <div *ngIf="userForm.controls.age.invalid && userForm.controls.age.touched"> <small *ngIf="userForm.controls.age.errors.required">Age is required.</small> <small *ngIf="userForm.controls.age.errors.min">Age must be at least 18.</small> <small *ngIf="userForm.controls.age.errors.max">Age must be less than or equal to 65.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form> ` }) export class UserFormComponent { userForm: FormGroup; constructor(private fb: FormBuilder) { this.userForm = this.fb.group({ firstName: ['', Validators.required], lastName: ['', Validators.required], age: ['', [Validators.required, Validators.min(18), Validators.max(65)]] }); } onSubmit() { if (this.userForm.valid) { console.log(this.userForm.value); } } }
Conclusion
In this section, we covered the essentials of form validation in Angular, including built-in validators, custom validators, and displaying validation messages. We also provided practical exercises to help reinforce the concepts. Understanding and implementing form validation is crucial for creating robust and user-friendly web applications. In the next section, we will delve into dynamic forms and how to handle complex form scenarios in Angular.
Angular Course
Module 1: Introduction to Angular
- What is Angular?
- Setting Up the Development Environment
- Angular Architecture
- First Angular Application
Module 2: Angular Components
- Understanding Components
- Creating Components
- Component Templates
- Component Styles
- Component Interaction
Module 3: Data Binding and Directives
- Interpolation and Property Binding
- Event Binding
- Two-Way Data Binding
- Built-in Directives
- Custom Directives
Module 4: Services and Dependency Injection
Module 5: Routing and Navigation
Module 6: Forms in Angular
Module 7: HTTP Client and Observables
- Introduction to HTTP Client
- Making HTTP Requests
- Handling HTTP Responses
- Using Observables
- Error Handling
Module 8: State Management
- Introduction to State Management
- Using Services for State Management
- NgRx Store
- NgRx Effects
- NgRx Entity
Module 9: Testing in Angular
Module 10: Advanced Angular Concepts
- Angular Universal
- Performance Optimization
- Internationalization (i18n)
- Custom Pipes
- Angular Animations