Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Custom Validators in Angular

Custom validators in Angular allow you to create your own validation logic to meet specific requirements. This tutorial covers the basics of creating and using custom validators effectively in your Angular applications.

What are Custom Validators?

Custom validators are functions that you define to encapsulate custom validation logic. They can be used to validate form controls beyond the built-in validators provided by Angular.

Creating a Custom Validator

Here is an example of a custom validator function that checks the strength of a password:

// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  userForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.userForm = this.fb.group({
      name: ['', [Validators.required, Validators.minLength(3)]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, this.passwordStrengthValidator]]
    });
  }

  passwordStrengthValidator(control: AbstractControl): ValidationErrors | null {
    const value = control.value;
    if (!value) {
      return null;
    }
    const hasUpperCase = /[A-Z]+/.test(value);
    const hasLowerCase = /[a-z]+/.test(value);
    const hasNumeric = /[0-9]+/.test(value);
    const passwordValid = hasUpperCase && hasLowerCase && hasNumeric;
    return !passwordValid ? { passwordStrength: true } : null;
  }

  onSubmit() {
    console.log('Form submitted!', this.userForm.value);
  }
}

// app.component.html
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Name</label>
    <input type="text" id="name" formControlName="name">
    <div *ngIf="userForm.get('name').invalid && userForm.get('name').touched">
      <div *ngIf="userForm.get('name').errors.required">Name is required</div>
      <div *ngIf="userForm.get('name').errors.minlength">Name must be at least 3 characters long</div>
    </div>
  </div>
  <div>
    <label for="email">Email</label>
    <input type="email" id="email" formControlName="email">
    <div *ngIf="userForm.get('email').invalid && userForm.get('email').touched">
      <div *ngIf="userForm.get('email').errors.required">Email is required</div>
      <div *ngIf="userForm.get('email').errors.email">Invalid email format</div>
    </div>
  </div>
  <div>
    <label for="password">Password</label>
    <input type="password" id="password" formControlName="password">
    <div *ngIf="userForm.get('password').invalid && userForm.get('password').touched">
      <div *ngIf="userForm.get('password').errors.required">Password is required</div>
      <div *ngIf="userForm.get('password').errors.passwordStrength">Password must include upper case, lower case, and numeric characters</div>
    </div>
  </div>
  <button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>

Using Custom Validators with FormGroup

Custom validators can be used with FormGroup to validate multiple controls together. Here is an example of a custom validator that checks if two passwords match:

// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  userForm: FormGroup;

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

  passwordMatchValidator(group: AbstractControl): ValidationErrors | null {
    const password = group.get('password').value;
    const confirmPassword = group.get('confirmPassword').value;
    return password === confirmPassword ? null : { passwordMismatch: true };
  }

  onSubmit() {
    console.log('Form submitted!', this.userForm.value);
  }
}

// app.component.html
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="password">Password</label>
    <input type="password" id="password" formControlName="password">
    <div *ngIf="userForm.get('password').invalid && userForm.get('password').touched">
      <div *ngIf="userForm.get('password').errors.required">Password is required</div>
    </div>
  </div>
  <div>
    <label for="confirmPassword">Confirm Password</label>
    <input type="password" id="confirmPassword" formControlName="confirmPassword">
    <div *ngIf="userForm.get('confirmPassword').invalid && userForm.get('confirmPassword').touched">
      <div *ngIf="userForm.get('confirmPassword').errors.required">Confirm Password is required</div>
      <div *ngIf="userForm.errors?.passwordMismatch">Passwords do not match</div>
    </div>
  </div>
  <button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>

Key Points

  • Custom validators encapsulate custom validation logic and can be reused across different form controls.
  • Custom validators are functions that return null if validation passes or an error object if validation fails.
  • Custom validators can be applied to individual form controls or FormGroups for cross-field validation.
  • Display validation messages conditionally based on the form control's state.

Conclusion

Custom validators in Angular provide a powerful way to implement bespoke validation logic that meets your application's specific needs. By understanding and using custom validators effectively, you can enhance the robustness and user-friendliness of your forms. Happy coding!