Почему DifferentUntilChanged не будет работать в asyncValidators в angular - PullRequest
2 голосов
/ 10 апреля 2020

Когда я по какой-то причине нажимаю клавишу на входе в форму, валидатор asyn c не обнаруживает DifferentUntilChanged и отправляет запросы API. например, если я нажимаю 35, удаляю 5 и после этого добавляю 5 снова, он все равно отправляет запрос. это код: (Я попробовал почти все, но все еще не работает)

validateSomeNumber(control: FormControl): Observable<any> | Promise <any> {
    this.isSubmitBtnDisabled = true;
    return control.valueChanges.pipe(
      debounceTime(1000),
      distinctUntilChanged(),
      switchMap((value) => {
        return this.apiService.someApiRequest({ 'to_number': control.value }).pipe(
          map(res => {
            console.log(res);
            if (res.success) {
              // console.log(res);
              this.isSubmitBtnDisabled = false;
              return null;
            } else {
              // console.log(res);
              this.isSubmitBtnDisabled = true;
              return{ 'invalidCharacters': true };
            }
          }),
        );
      }),
      first()
    );
  }

1 Ответ

1 голос
/ 10 апреля 2020

По умолчанию validateSomeNumber вызывается после каждого изменения значения.

Если вы возвращаете это при каждом изменении значения

return control.valueChanges.pipe(
  debounceTime(1000),
  distinctUntilChanged(),
  ...
)

вы создаете новую Наблюдаемость изменений значения при каждом изменении значения. изменение значения. Например, если вы наберете четыре символа, вы получите четыре независимых Observable, каждый из которых испускает один символ, а не один Observable, испускающий четыре раза. Таким образом, debounceTime и distinctUntilChanged будут влиять только на Наблюдаемую информацию, которую вы создаете, на конкретное изменение значения, но не на процесс изменения значения в целом. Если они влияют только на Observable, который излучает, как только они, очевидно, не работают так, как вы намереваетесь.

Вы должны вернуть http-запрос напрямую

validateSomeNumber(control: FormControl): Observable<any> | Promise <any> {
  this.isSubmitBtnDisabled = true;
  return this.apiService.someApiRequest({ 'to_number': control.value }).pipe(
      map(..),
  );
}

Ограничение частоты запросов

Опция 1: updateOn

Для предотвращения выполнения запроса http при каждом изменении значения Angular рекомендует изменить свойство updateOn на submit или blur.

С шаблонными формами:

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

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

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

{updateOn: 'blur'} будут выполнять валидаторы только тогда, когда Ваш ввод теряет фокус.

Вариант 2: эмулировать debounceTime и diver-only-UntilChanged

Angular автоматически отписывается от предыдущего Observable, возвращаемого AsyncValidator, если изменяется значение формы. Это позволяет вам эмулировать debounceTime с timer. Чтобы подражать distinctUntilChanged, вы можете отслеживать последний термин запроса и самостоятельно проверять равенство.

private lastRequestTerm = null;

validateSomeNumber(control: FormControl): Observable<any> | Promise <any> {
  this.isSubmitBtnDisabled = true;
  // emulate debounceTime
  return timer(1000).pipe(
    // emulate distinceUntilChanged
    filter(_ => control.value != this.lastRequestTerm),
    switchMap(() => {
      this.lastSearchTerm = control.value;
      return this.apiService.someApiRequest({ 'to_number': control.value });
    }),
    map(..)
  );
}
...