Асинхронная проверка поля формы не выполняет HTTP-вызов - PullRequest
0 голосов
/ 04 апреля 2019

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

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

Определение формы контроля:

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 && 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-ответ, состоящий из ips, которые соответствуют значению элемента управления. Метод отлично работает, используя .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(, он не достигает метода rest API, который извлекает ips из БД. Я попытался использовать систему подписки, и она действительно получает ips, но я не думаю, что именно так он должен возвращать 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);
          });
    }
  }
}

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

1 Ответ

1 голос
/ 04 апреля 2019

Если вы посмотрите на сигнатуру 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) в качестве параметра третий (один для асинхронных валидаторов) вместо массива параметра second .

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