AbstractControl не содержит асинхронную ошибку проверки после добавления таймера - PullRequest
0 голосов
/ 07 ноября 2018

Я создаю регистрационную форму с реактивными формами, где клиент должен вставить адрес электронной почты. Я добавил асинхронный валидатор в этот элемент управления, чтобы проверить, используется ли уже введенное электронное письмо.

this.form = this.formBuilder.group({
  ...,
  emailGroup: this.formBuilder.group({
    email: ['', [Validators.required, Validators.email], uniqueEmailValidator(this.registerService)],
    confirmEmail: ['', [Validators.required]]
  }, { validator: emailMatcher }),
  ...
});

Мой HTML выглядит так:

<div class="col-sm-6">
  <div class="form-group">
    <label for="reg-email">E-mailadres</label>
    <input class="form-control" type="text" id="reg-email" formControlName="email" [ngClass]="{'is-invalid': form.get('emailGroup.email').errors && (form.get('emailGroup.email').touched || isSubmitted)}">
    <div class="invalid-feedback">
      <div *ngIf="form.get('emailGroup.email').errors?.required || form.get('emailGroup.email').errors?.email">
        Please insert a valid email
      </div>
      <div *ngIf="form.get('emailGroup.email').errors?.uniqueEmail">                
        This email is already in use
      </div>
    </div>
  </div>
</div>

Первоначально мой асинхронный валидатор выглядит так:

export function uniqueEmailValidator(registerService: RegisterService): AsyncValidatorFn {
    return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
        return registerService.getCustomersByEmail(c.value).pipe(
            map(customers => {
                return customers && customers.length > 0 ? { 'uniqueEmail': true } : null;
            })
        );
    }
}

Все работает правильно до сих пор. Когда я вставляю существующее письмо, я получаю сообщение об ошибке «это письмо уже используется».

Я заметил, что этот асинхронный валидатор выполнялся для каждого вставленного символа, и по соображениям производительности я хочу этого избежать. Я решил добавить таймер на 500 мс и выполнять асинхронную проверку только тогда, когда нет активности в течение 500 мс. Это меняет мой асинхронный валидатор на это:

export function uniqueEmailValidator(registerService: RegisterService): AsyncValidatorFn {
    return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
        return timer(500).pipe(
            map(x => {
                return registerService.getCustomersByEmail(c.value).pipe(
                    map(customers => {
                        return customers && customers.length > 0 ? { 'uniqueEmail': true } : null;
                    })
                );
            })
        );
    };
}

Валидатор выполняет работу правильно, а элемент управления электронной почтой помечается как недействительный после асинхронной проверки. Проблема в том, что мой html больше не отображает сообщение об ошибке «Это письмо уже используется». Код ошибки «uniqueEmail» не добавляется в объект ошибок моего элемента управления.

Может кто-нибудь пролить свет на этот? Заранее спасибо.

1 Ответ

0 голосов
/ 07 ноября 2018

Мне нужно было то же самое. Так что я сделал это немного по-другому. Я создал асинхронный метод проверки, который возвращает обещание ошибки проверки в случае ошибки. Таким образом, этот метод задерживает вызов на сервер на 500 мс, и если есть какие-либо изменения во время задержки, он отменяет предыдущий тайм-аут и запускает новый. Таким образом, в конечном итоге на сервер будет отправлен только один вызов, если пользователь печатает. Посмотрите ниже.

Объявите эти две переменные

validationDelay: any;
validateUniqueEmail: any;

Определите следующий метод асинхронной проверки. Помните, что я использовал экземпляр var, потому что не мог использовать контекст this в обещании. Так что не путайся.

validateEmail( c: FormControl): Promise<{[key: string]: any}> {
const instance = this;
return new Promise(resolve => {
  if (instance.validationDelay) {
    clearTimeout(instance.validationDelay);
  }
  instance.validationDelay = setTimeout(() => {
   instance.registerService.getCustomersByEmail(c.value)
    .subscribe((customers) => {
      if (customers && customers.length > 0) {
        resolve({
          uniqueEmail: true
        });
      } else {
        resolve(null);
      }
    }, (err) => {
      resolve(null);
    });
  }, 500);
});
}

Теперь, чтобы использовать этот асинхронный метод. Инициируйте это следующим образом

ngOnInit(): void {
 this.validateUniqueEmail = (control: FormControl) => {
  return this.validateEmail(control);
 };
}

Используйте это validateUniqueEmail в вашем FormControl

email: ['', [Validators.required, Validators.email], this.validateUniqueEmail]

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