Проверка асинхронности поля формы, не выполняющая HTTP-вызов

#angular #validation #angular7

#angular #проверка #angular7

Вопрос:

Я создаю приложение Angular NodeJS SQLite. В одном из моих представлений мне нужно ввести IP-адрес в реактивной форме. Этот IP-адрес должен быть уникальным в базе данных, поэтому я использую асинхронный валидатор для проверки каждого ввода символа, если это значение находится в БД.

Следуя документации angular и некоторым видеороликам, мне удалось собрать этот код:

Определение элемента управления формой:

 createForm() {
    this._addNodoForm = this._formBuilder.group({
        name: [this.nodo.name,[Validators.required]],
        ip: [this.nodo.ip,[Validators.required, uniqueIPValidator(this._nodeService)]],
        status: [this.nodo.status, [Validators.required, Validators.maxLength(1)]],
        vbus_ip: [this.nodo.vbus_ip, [Validators.required]],
        physical_address: [this.nodo.physical_address, [Validators.required]],
        tunnel_address: [this.nodo.tunnel_address, [Validators.required]],
        transfer_rate: [this.nodo.transfer_rate, [Validators.required, Validators.max(9600), Validators.min(0)]],
    });

}
  

Определение класса проверки:

 export function uniqueIPValidator(nodeService: NodeService): AsyncValidatorFn {
  return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    if(c.value!=''){
        return nodeService.getUniqueIp(c.value).pipe(map(
          (addresses :any)=> {
            return (addresses amp;amp; addresses > 0) ? {"uniqueIP": true} : null;
          }));
    }
  }
}

  @Directive({

    selector: '[uniqueIP]',
    providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: UniqueIpValidatorDirective, multi: true }]
  })


  @Injectable()
  export class UniqueIpValidatorDirective implements AsyncValidator{
    constructor(private nodeService: NodeService) { }
    validate(ctrl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
      return uniqueIPValidator(this.nodeService)(ctrl);
    }
  }
  

nodeService.getUniqueIp(): этот метод возвращает HTTP-ответ, состоящий из IP-адресов, которые соответствуют управляющему значению. Метод отлично работает с использованием .subscribe()

  getUniqueIp(ip:string):Observable<any>{
        return this._http.get(this.url   'unique-ip/'   ip);
    }
  

И, наконец, HTML-код ввода:

 <input type="text" formControlName="ip" class="form-control" uniqueIP>
<div *ngIf="_addNodoForm.get('ip').errors?.uniqueIP">IP must be unique</div>
  

Проблема в том, что HTTP-вызов даже не выполняется с использованием .pipe(map( он не достигает метода API rest, который извлекает IP-адреса из базы данных. Я пытался использовать систему подписки, и она действительно извлекает IP-адреса, но я не думаю, что именно так она должна возвращать Observable<ValidationsErrors> , поэтому в форме также не отображается ошибка.

 export function uniqueIPValidator(nodeService: NodeService): AsyncValidatorFn {
  return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    if(c.value!=''){//to avoid making the http call when the input is empty
        return nodeService.getUniqueIp(c.value).pipe().
          subscribe(addresses => {
            console.log('DIR: ' addresses);
            if(addresses!=null){
              return {"uniqueIP": true};
            }
          },error=>{
            console.log(error);
          });
    }
  }
}
  

Из теории я знаю, что асинхронные валидаторы запускаются только тогда, когда валидаторы синхронизации возвращают значение null, но я действительно не знаю, что это означает в данном случае, может ли это быть проблемой?
Это только для образовательных приложений, поскольку я пытаюсь понять асинхронные валидаторы, чтобы я мог использовать их в будущем. Приветствуются любые предложения о проблеме или самом сообщении.

Ответ №1:

Если вы посмотрите на подпись для FormControl в документах, вы увидите, что параметры конструктора являются:

 formState: any = null, 
validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], 
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]
  

Я разделил параметры на их отдельные строки, чтобы подчеркнуть, что их три.

Я полагаю, что ваша проблема может заключаться в том, что вы смешиваете свой uniqueIPValidator AsyncValidatorFn с синхронным Validators.required ValidatorFn .

Попробуйте изменить:

ip: [this.nodo.ip,[Validators.required, uniqueIPValidator(this._nodeService)]],

Для

ip: [this.nodo.ip, Validators.required, uniqueIPValidator(this._nodeService)],

Делая это, вы будете предоставлять uniqueIPValidator(this._nodeService) параметр в качестве третьего параметра (для асинхронных валидаторов) вместо того, чтобы внутри массива второго параметра.

Комментарии:

1. Именно то, что мне было нужно, спасибо! Думаю, мне нужно еще раз прочитать документы формы.

2. Добро пожаловать! Я рад, что это решило вашу проблему. Честно говоря, это была очень простая ошибка 🙂