We use cookies to enhance your experience on the site
CodeWorlds

Form Validation

Built-in Validators

1import { Validators } from '@angular/forms';
2
3this.fb.group({
4  // Required field
5  name: ['', Validators.required],
6
7  // Email
8  email: ['', [Validators.required, Validators.email]],
9
10  // Length
11  password: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(50)]],
12
13  // Numeric range
14  age: [0, [Validators.min(18), Validators.max(120)]],
15
16  // Regex pattern
17  phone: ['', Validators.pattern(/^\d{9}$/)],
18
19  // Required true (checkbox)
20  acceptTerms: [false, Validators.requiredTrue]
21});

Custom Validators

1import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
2
3// Synchronous validator
4function forbiddenNameValidator(forbiddenNames: string[]): ValidatorFn {
5  return (control: AbstractControl): ValidationErrors | null => {
6    if (forbiddenNames.includes(control.value?.toLowerCase())) {
7      return { forbiddenName: { value: control.value } };
8    }
9    return null;
10  };
11}
12
13// Password strength validator
14function strongPasswordValidator(): ValidatorFn {
15  return (control: AbstractControl): ValidationErrors | null => {
16    const value = control.value;
17    if (!value) return null;
18
19    const hasUpperCase = /[A-Z]/.test(value);
20    const hasLowerCase = /[a-z]/.test(value);
21    const hasNumeric = /[0-9]/.test(value);
22    const hasSpecial = /[!@#$%^&*]/.test(value);
23
24    const isValid = hasUpperCase && hasLowerCase && hasNumeric && hasSpecial;
25
26    return isValid ? null : {
27      weakPassword: {
28        hasUpperCase,
29        hasLowerCase,
30        hasNumeric,
31        hasSpecial
32      }
33    };
34  };
35}
36
37// Usage
38this.fb.group({
39  name: ['', [Validators.required, forbiddenNameValidator(['admin', 'root'])]],
40  password: ['', [Validators.required, strongPasswordValidator()]]
41});

Async Validator

1import { AsyncValidatorFn } from '@angular/forms';
2import { map, catchError, debounceTime, switchMap, first } from 'rxjs/operators';
3import { of } from 'rxjs';
4
5function uniqueNameValidator(samuraiService: SamuraiService): AsyncValidatorFn {
6  return (control: AbstractControl) => {
7    return of(control.value).pipe(
8      debounceTime(300),
9      switchMap(name =>
10        samuraiService.checkNameExists(name).pipe(
11          map(exists => exists ? { nameTaken: true } : null),
12          catchError(() => of(null))
13        )
14      ),
15      first()
16    );
17  };
18}
19
20// Usage - third argument is async validators
21this.fb.group({
22  name: ['',
23    [Validators.required],
24    [uniqueNameValidator(this.samuraiService)]
25  ]
26});
Go to CodeWorlds