Skip to main content
Version: 0.10.0

unique

Asynchronously checks that the value is unique in the backend.

Signature

NguardValidators.Async.unique(config: AsyncValidatorConfig): AsyncValidatorFn

AsyncValidatorConfig

FieldTypeDefaultDescription
endpointstringURL to check against
method'GET' | 'POST' | 'PUT''GET'GET sends the value as a query param; POST/PUT in the body
paramNamestring'value'Key carrying the value
debounceTimenumber300Debounce (ms) before the request
resolve(response: HttpResponse | HttpErrorResponse) => boolean | nullstatus-code ruleYour own verdict from the full response — true = valid, false = invalid, null = undecided (valid)

Default rule (no resolve)

Status code only — the library never assumes a response body shape:

ResponseMeaningResult
2xxthe value exists (taken)invalid { unique: true }
404not found (free)valid
anything else (5xx, network)undecidedvalid (don't block)

Reactive forms

import { FormControl } from '@angular/forms';
import { NguardValidators } from 'ng-nguard';

// In a component field (an injection context — the factory calls inject(HttpClient))
username = new FormControl('', {
asyncValidators: [NguardValidators.Async.unique({ endpoint: '/api/users/check-username' })],
});

Template-driven forms

<input ngModel name="username" [nguardUnique]="{ endpoint: '/api/users/check-username' }" />

Custom rule

Most backends are not REST-compliant and won't signal availability by status code — so define your own rule from the whole response (status, headers, or a body however it is nested):

import { HttpResponse } from '@angular/common/http';

NguardValidators.Async.unique({
endpoint: '/api/users/check-username', // always returns 200 with { data: { taken: boolean } }
resolve: (res) => (res instanceof HttpResponse ? (res.body as { data: { taken: boolean } }).data.taken === false : null),
});

Error key

{ unique: true }

Notes

  • Must be created in an injection context (component field/constructor); the directive handles this for you.
  • Debounced; Angular cancels the in-flight request on the next change. control.pending is true while it runs.
  • Empty values pass without a request. Transport/server failures resolve to undecided (valid) so they don't block submission.

See also