表单字段异步验证未执行HTTP调用

时间:2019-04-04 09:01:14

标签: angular validation angular7

我正在创建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(执行,它没有到达从数据库检索ip的API rest方法。我尝试使用订阅系统,但实际上确实检索了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);
          });
    }
  }
}

从理论上我知道异步验证器仅在同步验证器返回null时才被触发,但是我真的不知道在这种情况下意味着什么,这可能是个问题吗? 这仅用于教育性小动物,因为我正试图了解异步验证器,以便将来我可以使用它们。关于问题或帖子本身的任何建议都将受到赞赏。

1 个答案:

答案 0 :(得分:1)

如果您在docs中查看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 数组的内部>参数。