我该如何对内部使用CombineLatest的Angular 7异步验证器进行反跳?

时间:2018-12-11 12:55:59

标签: angular rxjs

我有点理解,其中涉及的工具将是pipetimerswitchMapdebounceTimedistinctUntilChanged,甚至可能更多,但是我无法弄清楚如何使它们与combineLatest一起使用。

以下验证器获取以逗号分隔的电子邮件列表,并对每个电子邮件执行API调用,以检查客户数据库中是否存在该电子邮件。

import {AbstractControl, AsyncValidatorFn, ValidationErrors, ValidatorFn} from "@angular/forms";
import {combineLatest} from "rxjs";
import {Observable} from "rxjs/internal/Observable";

import {UtilityApiService} from "../../services/api/utility-api.service";

/**
 * The email address must exist in the database and belong to a customer.
 * It works both with a single email or a comma separate list of emails. In case of a list, it will only validate
 * as a success if ALL emails belong to a customer.
 * @returns {ValidatorFn}
 * @constructor
 */
export class CustomerEmailCsvValidator {
    public static createValidator(internalApiService: UtilityApiService): AsyncValidatorFn {
        return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
            return new Observable((observer) => {
                if (!control.value) {
                    observer.next(null);
                    return;
                }

                const emails: string[] = control.value.split(",").map(email => email.trim());
                const observables: Observable<boolean>[] = emails.map(email => {
                    return internalApiService.isCustomerEmail(email);
                });

                combineLatest(observables).subscribe((responses: boolean[]) => {
                    if (responses.every(value => value)) {
                        // All emails exist and belong to customers. Therefore no error.
                        observer.next(null);
                    } else {
                        // One or more emails do not exist in the database, or do not belong to a customer.
                        // This is an error for this validator.
                        observer.next({customerEmail: true});
                    }
                    observer.complete();
                });
            });
        };
    }
}

如何消除抖动,以使其在750毫秒内不多次运行API调用?

1 个答案:

答案 0 :(得分:0)

这对我最终有用:

import {AbstractControl, AsyncValidatorFn, ValidationErrors, ValidatorFn} from "@angular/forms";
import {combineLatest, of, timer} from "rxjs";
import {Observable} from "rxjs/internal/Observable";
import {map, switchMap} from "rxjs/operators";

import {UtilityApiService} from "../../services/api/utility-api.service";

/**
 * The email address must exist in the database and belong to a customer.
 * It works both with a single email or a comma separated list of emails. In case of a list, it will only validate
 * as a success if ALL emails belong to a customer.
 * @returns {ValidatorFn}
 * @constructor
 */
export class CustomerEmailCsvValidator {
    public static createValidator(internalApiService: UtilityApiService): AsyncValidatorFn {
        return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
            return timer(750).pipe(switchMap(() => {
                if (!control.value) {
                    return null;
                }

                const emails: string[] = control.value.split(",").map(email => email.trim());
                const observables: Observable<boolean>[] = emails.map(email => {
                    return internalApiService.isCustomerEmail(email);
                });

                return combineLatest(observables).pipe(map((responses: boolean[]) => {
                    if (responses.every(value => value)) {
                        // All emails exist and belong to customers. Therefore no error.
                       return null;
                    } else {
                        // One or more emails do not exist in the database, or do not belong to a customer.
                        // This is an error for this validator.
                        return {customerEmail: true};
                    }
                }));
            }));
        };
    }
}