How to add debounce time to an async validator in angular 2?
Angular 4+, Using Observable.timer(debounceTime)
:
@izupet 's answer is right but it is worth noticing that it is even simpler when you use Observable:
emailAvailability(control: Control) { return Observable.timer(500).switchMap(()=>{ return this._service.checkEmail({email: control.value}) .mapTo(null) .catch(err=>Observable.of({availability: true})); });}
Since angular 4 has been released, if a new value is sent for checking, Angular unsubscribes from Observable
while it's still paused in the timer, so you don't actually need to manage the setTimeout
/clearTimeout
logic by yourself.
Using timer
and Angular's async validator behavior we have recreated RxJS debounceTime
.
Keep it simple: no timeout, no delay, no custom Observable
// assign the async validator to a fieldthis.cardAccountNumber.setAsyncValidators(this.uniqueCardAccountValidatorFn());// or like thisnew FormControl('', [], [ this.uniqueCardAccountValidator() ]);
// subscribe to control.valueChanges and define pipeuniqueCardAccountValidatorFn(): AsyncValidatorFn { return control => control.valueChanges .pipe( debounceTime(400), distinctUntilChanged(), switchMap(value => this.customerService.isCardAccountUnique(value)), map((unique: boolean) => (unique ? null : {'cardAccountNumberUniquenessViolated': true})), first()); // important to make observable finite}
It is actually pretty simple to achieve this (it is not for your case but it is general example)
private emailTimeout;emailAvailability(control: Control) { clearTimeout(this.emailTimeout); return new Promise((resolve, reject) => { this.emailTimeout = setTimeout(() => { this._service.checkEmail({email: control.value}) .subscribe( response => resolve(null), error => resolve({availability: true})); }, 600); });}