Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Angular Dictionary
  3. Validation

Validation

Since: Angular 14(2022)

Validation in Angular is a mechanism for defining rules to verify form input values. It is available in both template-driven forms and reactive forms, and supports built-in validators such as required input, minimum/maximum length, and regular expression patterns, as well as custom validators you create yourself. Validation results can be referenced from the template through the errors object, and used for displaying error messages and controlling the submit button.

Built-in Validator List

ValidatorTemplate-DrivenReactive (Validators)Description
RequiredrequiredValidators.requiredValidates that the value is not empty.
Minimum lengthminlength="N"Validators.minLength(N)Validates that the string length is N characters or more.
Maximum lengthmaxlength="N"Validators.maxLength(N)Validates that the string length is N characters or fewer.
Patternpattern="regex"Validators.pattern('regex')Validates that the input value matches the specified regular expression.
EmailemailValidators.emailValidates that the input value is in email address format.
Minimum valuemin="N"Validators.min(N)Validates that the number is N or greater.
Maximum valuemax="N"Validators.max(N)Validates that the number is N or less.

Sample Code

An example of using built-in validators in a template-driven form.

// register.component.ts
// A component that validates a user registration form with template-driven forms.
// Import FormsModule to use ngModel and built-in validators.

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

@Component({
  selector: 'app-register',
  standalone: true,
  imports: [FormsModule],
  template: `
    <form #registerForm="ngForm" (ngSubmit)="onSubmit(registerForm)">

      <div>
        <label for="name">Name</label>
        <input
          id="name"
          name="name"
          [(ngModel)]="name"
          required
          minlength="2"
          maxlength="20"
          #nameCtrl="ngModel"
        />
        <div *ngIf="nameCtrl.invalid && nameCtrl.touched">
          <span *ngIf="nameCtrl.errors?.['required']">Name is required.</span>
          <span *ngIf="nameCtrl.errors?.['minlength']">Please enter at least 2 characters.</span>
        </div>
      </div>

      <div>
        <label for="email">Email address</label>
        <input
          id="email"
          name="email"
          type="email"
          [(ngModel)]="email"
          required
          email
          #emailCtrl="ngModel"
        />
        <div *ngIf="emailCtrl.invalid && emailCtrl.touched">
          <span *ngIf="emailCtrl.errors?.['required']">Email address is required.</span>
          <span *ngIf="emailCtrl.errors?.['email']">Please enter a valid email address.</span>
        </div>
      </div>

      <button type="submit" [disabled]="registerForm.invalid">Register</button>
    </form>
  `,
})
export class RegisterComponent {
  name: string = '';
  email: string = '';

  onSubmit(form: any): void {
    if (form.valid) {
      console.log('Submitted:', { name: this.name, email: this.email });
    }
  }
}

An example of using Validators in a reactive form.

// login.component.ts
// A component that validates a login form with reactive forms.
// Combine FormBuilder and Validators to define validation rules.

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

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [ReactiveFormsModule, CommonModule],
  template: `
    <form [formGroup]="loginForm" (ngSubmit)="onSubmit()">

      <div>
        <label for="email">Email address</label>
        <input id="email" type="email" formControlName="email" />
        <div *ngIf="loginForm.get('email')?.invalid && loginForm.get('email')?.touched">
          <span *ngIf="loginForm.get('email')?.errors?.['required']">Email address is required.</span>
          <span *ngIf="loginForm.get('email')?.errors?.['email']">Please enter a valid format.</span>
        </div>
      </div>

      <div>
        <label for="password">Password</label>
        <input id="password" type="password" formControlName="password" />
        <div *ngIf="loginForm.get('password')?.invalid && loginForm.get('password')?.touched">
          <span *ngIf="loginForm.get('password')?.errors?.['required']">Password is required.</span>
          <span *ngIf="loginForm.get('password')?.errors?.['minlength']">Please enter at least 8 characters.</span>
        </div>
      </div>

      <button type="submit" [disabled]="loginForm.invalid">Log in</button>
    </form>
  `,
})
export class LoginComponent {
  loginForm: FormGroup = this.fb.group({
    email:    ['', [Validators.required, Validators.email]],
    password: ['', [Validators.required, Validators.minLength(8)]],
  });

  constructor(private fb: FormBuilder) {}

  onSubmit(): void {
    if (this.loginForm.valid) {
      console.log('Login info:', this.loginForm.value);
    }
  }
}

An example of creating a custom validator and applying it to a reactive form.

// custom-validators.ts
// A file that defines custom validation functions for the app.
// Returning a function of type ValidatorFn conforms to Angular's validator specification.

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

// A validator that checks whether two password fields match.
// Applied at the FormGroup level.
export function passwordMatchValidator(): ValidatorFn {
  return (group: AbstractControl): ValidationErrors | null => {
    const password = group.get('password')?.value;
    const confirm  = group.get('confirmPassword')?.value;

    // Skip validation if either field is empty
    if (!password || !confirm) {
      return null;
    }

    return password === confirm ? null : { passwordMismatch: true };
  };
}

// A validator that allows only alphabetic characters and hyphens (for usernames).
export function usernameValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const value: string = control.value;

    // Return null if empty — let required handle it
    if (!value) {
      return null;
    }

    const isValid = /^[a-zA-Z0-9_-]+$/.test(value);

    return isValid ? null : { invalidUsername: true };
  };
}
// signup.component.ts
// A member registration form component with custom validators applied.

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { usernameValidator, passwordMatchValidator } from './custom-validators';

@Component({
  selector: 'app-signup',
  standalone: true,
  imports: [ReactiveFormsModule, CommonModule],
  template: `
    <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">

      <div>
        <label for="username">Username</label>
        <input id="username" formControlName="username" />
        <div *ngIf="signupForm.get('username')?.invalid && signupForm.get('username')?.touched">
          <span *ngIf="signupForm.get('username')?.errors?.['required']">Username is required.</span>
          <span *ngIf="signupForm.get('username')?.errors?.['invalidUsername']">Only letters, numbers, hyphens, and underscores are allowed.</span>
        </div>
      </div>

      <div>
        <label for="pw">Password</label>
        <input id="pw" type="password" formControlName="password" />
      </div>

      <div>
        <label for="cpw">Confirm Password</label>
        <input id="cpw" type="password" formControlName="confirmPassword" />
        <div *ngIf="signupForm.errors?.['passwordMismatch'] && signupForm.get('confirmPassword')?.touched">
          Passwords do not match.
        </div>
      </div>

      <button type="submit" [disabled]="signupForm.invalid">Register</button>
    </form>
  `,
})
export class SignupComponent {
  signupForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.signupForm = this.fb.group(
      {
        username:        ['', [Validators.required, usernameValidator()]],
        password:        ['', [Validators.required, Validators.minLength(8)]],
        confirmPassword: ['', Validators.required],
      },
      { validators: passwordMatchValidator() }
    );
  }

  onSubmit(): void {
    if (this.signupForm.valid) {
      console.log('Registration data:', this.signupForm.value);
    }
  }
}

Control State Flag List

PropertyDescription
valid / invalidIndicates whether all validations have passed or not.
touched / untouchedIndicates whether the field has lost focus at least once. Used to show errors at the right time.
dirty / pristineIndicates whether the value has been changed at least once.
pendingIndicates that an async validator has not yet completed.
errorsAn object holding validation error keys and details. Returns null when there are no errors.

Important Notes

ItemDescription
Template-driven vs ReactiveTemplate-driven forms are suited for smaller forms, while reactive forms are better for complex validation logic and dynamic form structures.
Using touchedShowing errors immediately when the page loads degrades the user experience. It is common practice to add touched as a condition so errors only appear after the user has left the field.
Custom validator return valueAlways return null when validation succeeds. Returning an error object marks validation as failed.
Cross-field validationValidation that spans multiple fields (such as password matching) should be applied at the FormGroup level.
Async validatorsUse AsyncValidatorFn for validations that require a server query (such as checking for duplicate usernames). Implement as a function that returns an Observable or Promise.

Overview

Validation in Angular is a flexible mechanism available in both template-driven forms and reactive forms. Built-in validators such as required and minlength cover most cases, and custom validators can be implemented for more complex verifications.

For error display timing, use touched and dirty to prevent errors from appearing before the user has interacted. When validation spanning multiple fields is needed, applying a validator at the FormGroup level is the correct approach.

For the basics of form usage, see ngModel. For managing form data with services, see Service.

If you find any errors or copyright issues, please .