Angular17 min read

Reactive Forms: Async Validators (Email Uniqueness)

Validate input using an API call, like checking if an email is already taken.

Liam Turner
August 3, 2025
3.8k106

Async validators are perfect when validation depends on server data.

Example:
- email already exists
- username already taken
- coupon code valid

## Step 1: Create an async validator

```ts
import { AbstractControl, AsyncValidatorFn } from '@angular/forms';
import { debounceTime, map, of, switchMap } from 'rxjs';
import { inject } from '@angular/core';
import { UsersApi } from './users.api';

export const emailAvailableValidator = (): AsyncValidatorFn => {
  const api = inject(UsersApi);

  return (control: AbstractControl) => {
    if (!control.value) return of(null);

    return of(control.value).pipe(
      debounceTime(400),
      switchMap(email => api.checkEmail(email)),
      map(res => (res.available ? null : { emailTaken: true }))
    );
  };
};
```

Assume backend returns: `{ available: true | false }`

## Step 2: Use it on a control

```ts
email: new FormControl('', {
  nonNullable: true,
  validators: [Validators.required, Validators.email],
  asyncValidators: [emailAvailableValidator()],
})
```

## Step 3: Show message in UI

```html
<div *ngIf="form.controls.email.errors?.['emailTaken']">
  This email is already registered.
</div>
```

## Important performance tip

Always debounce async validators, otherwise you spam the API on every keystroke.

> Next: Custom form controls with ControlValueAccessor.
#Angular#Forms#Advanced