ค้นหาเว็บไซต์

typescript - Angular Async Validator FormControls จะไม่อัปเดตจนกว่าจะมีการคลิกออกจากช่องกรอก


ตัวตรวจสอบ Async ของฉันมีลักษณะดังนี้:

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;
        })
      })
    )
    }
  }

ปัญหากับ Async Validator ของฉันคือ FormControls ของฉันที่ถูกเพิ่มเข้าไปใน FormArray จะไม่รับรู้ 'สถานะ' ปัจจุบันของตัวเองจนกว่าจะมีการละสายตา

นี่คือ 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>

div ที่มีคลาส "url-pending" ปรากฏขึ้น และจากนั้นมันก็ไม่หายไป - แม้ว่าจะมีการตรวจสอบ FormControl ที่มันขึ้นอยู่กับจากฝั่งเซิร์ฟเวอร์แล้ว - จนกว่าผู้ใช้จะออกจาก FormControl ที่ div ขึ้นอยู่ด้วย

คำถาม stackoverflow เพียงข้ออื่นเดียวที่คล้ายกับเรื่องนี้ก็คือ ลิงก์นี้ ฉันไม่สามารถเข้าใจคำแนะนำในลิงก์นั้นได้อย่างเต็มที่ และความซับซ้อนเพิ่มเติมที่ฉันมีเมื่อเทียบกับผู้โพสต์ในลิงก์คือ ฉันมีไอคอนในฟอร์มของฉันที่มีรูปเครื่องหมายบวก เพื่อให้ผู้ใช้สามารถเพิ่ม FormControls ลงใน FormArray ได้ ฉันไม่สามารถหาวิธีเพิ่ม directives ให้กับ FormControls ที่ผู้ใช้เพิ่มโดยการโต้ตอบกับฟอร์ม

ฉันจะตอบคำถามของตัวเองเพราะฉันหาวิธีแก้ปัญหานี้ได้แล้ว แต่ฉันแก้ปัญหาในแบบที่ค่อนข้าง 'แฮ็ก' ถ้าใครคนอื่นรู้คำตอบที่ดีกว่านี้ กรุณาตอบกลับด้วย

คำตอบ #1

ฉันได้เพิ่มตัวระบุลงใน 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$ ใน Async Validator ภายใน callback ของตัวดำเนินการ ฉันมุ่งเน้นไปที่ FormControl แต่ละตัวของ FormArray แล้วจากนั้นก็ทำการ blur มัน

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 จะไม่ละสายตาและสถานะ 'ค้างรอดำเนินการ' จะคงอยู่ตลอดบนหน้าจอ (แต่ไม่ส่งผลต่อการทำงานจริง)

คำตอบ #2

ฉันเจอปัญหาคล้าย ๆ กัน; อย่างไรก็ตามฉันสามารถแก้ไขได้โดยการส่ง statusChanges ไปยัง async

{{field.statusChanges | async}}
or 
...*ngIf="(field.statusChanges | async) === 'PENDING'"...

ดังนั้นในกรณีของคุณ:

<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].statusChanges | async) === 'PENDING'">
                Validating...
        </div>
    </div>
</div>

แหล่งที่มา

  • https://angular.io/guide/form-validation#async-validation