Отменить асинхронный валидатор - PullRequest
0 голосов
/ 10 октября 2018

У меня есть работающий асинхронный валидатор, который отправляет 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));
  }

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

Мне удалось решить эту проблему другим способом, с помощью свойства ' updateOn ' в элементе управления.

С формами на основе шаблонов:

<input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}">

С реактивными формами:

new FormControl('', {updateOn: 'blur'});

Если вы используете конструктор форм, начиная с Angular 7, вы можете использовать this :

this.form = this._fb.group({
  email: ['', [CustomValidators.email], null, 'blur'],
});
0 голосов
/ 17 мая 2019

Используя наблюдаемые, я сделал:

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)
            ))
        );
    }
0 голосов
/ 10 октября 2018

Это должно сработать:

  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 принимает управляющее значение и запускает запрос на получение к бэкэнду и передает новое наблюдаемое на следующий этаптрубопровода.Наконец, я применил ваш существующий оператор карты к результату из бэкэнда, чтобы сгенерировать соответствующее сообщение об ошибке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...