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
