[英]Debounce async Validator
我有一個工作異步驗證器,它向服務器發出 HTTP 請求以檢查用戶名是否已被占用。 因為我不想在每次擊鍵后調用 API,所以我需要對輸入流進行去抖動。
我第一次throttleTime
的服務,但對SO另一個話題說,這已經是對誰訂閱了一個,但還沒有運氣!
我的組件:
this.form = this._fb.group(
{
username: ['', [Validators.required, Validators.maxLength(50), NoWhitespaceValidator], [IsUserIdFreeValidator.createValidator(this._managementService)]]
});
我的驗證器:
export class IsUserIdFreeValidator {
static createValidator(_managementService: ManagementService) {
return (control: AbstractControl) => {
return _managementService.isUserIdFree(control.value)
.pipe(
throttleTime(5000),
(map(
(result: boolean) => result === false ? { isUserIdFree: true } : null))
);
};
}
}
我的服務:
public isUserIdFree(userId: string): Observable<{} | boolean | HttpError> {
const updateUserCheck: UpdateUserCheck = new UpdateUserCheck();
updateUserCheck.userID = userId;
return this._httpClient.post<boolean>('UserManagementUser/IsUserIdFree', updateUserCheck));
}
這應該可以解決問題:
static createValidator(_managementService: ManagementService) {
const subject = new BehaviorSubject('');
const observable = subject.asObservable().pipe(
debounceTime(1000),
switchMap(val => _managementService.isUserIdFree(val)),
map((isUserIdFree: boolean) => isUserIdFree ? null : { userIdTaken : true }),
);
return (control: AbstractControl) => {
subject.next(control.value);
return observable.pipe(takeUntil(timer(5000))); // acts as a way to make observable finite
}
}
去抖動應該發生在控件發出的值上,而不是從 http 服務返回的結果上。 我們首先在可觀察流上發出值,並通過distinctUntilChanged
將其通過管道傳輸,這確保只有與上次發出的值相比的不同值才能通過管道的那個階段。 debounceTime(x)
確保僅在發出 'x' 毫秒后的最后一個值。
switchMap
操作符獲取控制值並向后端發出 get 請求,並將新的 observable 傳遞到管道的下一個階段。 最后,我已將您現有的地圖運算符應用於后端的結果以生成適當的錯誤消息。
使用 observables,我做了:
form = this._fb.group({
email: [null, [Validators.required, Validators.email], [this.validateEmailNotTaken.bind(this)]]
})
private _emailCancel$ = new Subject<void>();
validateEmailNotTaken(control: AbstractControl): Observable<object> {
this._emailCancel$.next();
return race(
timer(3000).pipe(map(_ => true)),
this._emailCancel$.pipe(
map(_ => false)
)
).pipe(
take(1),
filter(val => !!val),
switchMap(() => this.isEmailTaken(control.value).pipe(
map(res => res ? {isTaken: true } : null)
))
);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.