首页 > 解决方案 > Angular Async Validator FormControls 在模糊之前不会更新

问题描述

我的异步验证器如下所示:

asyncValidator(service:ApiCallsService):AsyncValidatorFn{
    return (control:FormControl):Promise<ValidationErrors | null> | Observable<ValidationErrors | null> =>{
    let timer$ = timer(2000);
     return timer$.pipe(
      take(1),
      switchMap(()=> {
        let videoId = service.checkUrl(control.value);
        return service.getVideoDescription(videoId).toPromise().then((val:any)=>{

          return (!val.id) ? {"invalidUrl": true} : null;
        })
      })
    )
    }
  }

我的异步验证器的问题在于,添加到我的 FormArray 中的 FormControl 在它们被模糊之前不会获取它们自身的当前“状态”。

这是我的 FormArray 和里面的 FormControl:

<div class="url-con" formArrayName="urls" >
    <div *ngFor="let url of urls.controls; let i=index" class="url-input-con">
        <input  minLength="5" placeholder="Video Url" class="url-input" [formControlName]="i">
        <div class="url-pending" *ngIf="urls.controls[i].pending && !urls.controls[i].valid">Validating...</div>
    </div>
</div>

具有“url-pending”类的 div 出现,然后它不会消失 - 即使它所依赖的 FormControl 由后端验证 - 直到用户模糊了 div 所依赖的 FormControl。

与此类似的唯一其他 stackoverflow 问题是此链接。我无法完全理解该链接的说明,并且与链接的海报相比,我遇到的另一个复杂情况是我的表单中有一个形状为加号的图标,以便用户可以向 FormArray 添加更多的 FormControl。我不知道如何向用户通过与表单交互添加的 FormControls 添加指令。

我会回答我自己的问题,因为我想出了如何解决这个问题,但我以一种“hackish”的方式解决了它。如果其他人对此有更好的答案,请回复。

标签: angulartypescriptangular-forms

解决方案


我向 formArray (#formArray) 添加了一个标识符:

<div #formArray class="url-con" formArrayName="urls" >
    <div *ngFor="let url of urls.controls; let i=index" class="url-input-con">
        <input  minLength="5" placeholder="Video Url" class="url-input" [formControlName]="i">
        <div class="url-pending" *ngIf="urls.controls[i].pending && !urls.controls[i].valid">Validating...</div>
    </div>
</div>

然后我将 finalize() 添加到异步验证器中 timer$ 的返回中。在操作符的回调中,我将 FormArray 的每个 FormControl 设为焦点,然后进行模糊处理。

asyncValidator(service:ApiCallsService):AsyncValidatorFn{
   return (control:FormControl):Promise<ValidationErrors | null> | Observable<ValidationErrors | null> =>{
   let timer$ = timer(2000);
    return timer$.pipe(
     take(1),
     switchMap(()=> {
       let videoId = service.checkUrl(control.value);
       return service.getVideoDescription(videoId).toPromise().then((val:any)=>{

         return (!val.id) ? {"invalidUrl": true} : null;
       })
     }),
     finalize(()=>{
         Array.from(this.formArray.nativeElement.children)
              .forEach((val:HTMLElement,ind)=>{
                   (Array.from(val.children)[0] as HTMLElement).focus();
                   (Array.from(val.children)[0] as HTMLElement).blur();
               })         
     })
   )
}
}

每个 FormControl 必须首先聚焦,因为如果用户在验证结束之前模糊,那么 FormControl 永远不会模糊,并且“待定”状态会永远持续显示(尽管在功能上不是)。


推荐阅读