tezvyn:

Implement an async Angular validator with HTTP and PENDING feedback

AI-drafted, machine-checkedSource: angular.devadvanced
Implement an async Angular validator with HTTP and PENDING feedback

Tests Angular async validator lifecycle and HTTP race conditions. A strong candidate returns an Observable from AsyncValidatorFn, lets Angular set PENDING automatically, debounces input, and binds control.pending in the template.

WHAT THIS TESTS: Whether the candidate understands the Angular Reactive Forms async validation contract, the AbstractControl status lifecycle, and how to prevent HTTP race conditions and memory leaks during user input validation. It also checks if they know the difference between updateOn change and blur and how that impacts backend load. This question separates engineers who have built production-grade forms from those who only use built-in required validators.

A GOOD ANSWER COVERS: First, implement AsyncValidatorFn and return an Observable of ValidationErrors or null, or a Promise. Angular automatically sets the control status to PENDING when async validation starts and resolves it to VALID or INVALID when the returned stream completes or the Promise settles. Second, never manually call markAsPending because the framework manages this state internally. Third, debounce the input to avoid request storms, usually by piping debounceTime inside the returned Observable so rapid keystrokes cancel the prior in-flight validation via Angular's internal unsubscribe behavior. Fourth, expose the pending state to the template with control.pending to render a loading indicator or disable submission. Fifth, ensure the Observable eventually emits and completes, because Angular waits for the first emission to resolve the status and will leave the control in PENDING otherwise.

COMMON WRONG ANSWERS: Calling control.markAsPending manually inside the validator instead of trusting Angular to handle it. Returning a plain object or synchronously throwing rather than returning an Observable or Promise. Subscribing to the HTTP call inside the validator with subscribe and not returning anything, which breaks Angular's cancellation mechanism and leaks memory. Failing to debounce so the backend receives a request on every keystroke. Checking control.status in the component TypeScript to toggle UI state instead of binding directly to pending in the template, which adds unnecessary change detection complexity.

LIKELY FOLLOW-UPS: How do you handle server errors during validation? The candidate should catch the error and map it to a validation error object or rethrow to avoid breaking the form. What happens if the user navigates away while validation is pending? Angular's internal subscription is tied to the control lifetime, so destroying the component cleans it up automatically. How do multiple async validators interact? Angular runs them in parallel when provided as an array to the async validators argument. Should you use a Promise or Observable? Observables are preferred because Angular can unsubscribe from them when the value changes, while Promises cannot be cancelled and may deliver stale results.

ONE CONCRETE EXAMPLE: Inject HttpClient into a UsernameValidator class implementing AsyncValidator. The validate method returns of(control.value).pipe(debounceTime(300), distinctUntilChanged(), switchMap(value => this.http.get(/api/check-username/${value})), map(isTaken => isTaken ? { usernameTaken: true } : null), catchError(() => of(null))). In the component template, show a spinner when form.get(username).pending is true and disable the submit button until the control status is VALID.

Read the original → angular.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.