angular - 在 form.setValues() 上非同步驗證會被觸發多次
我正在使用 Angular 5,響應式表單的方法。
我在一個 Angular Material 對話框中有一個表單,我用它來輸入和編輯資料。我的建構子看起來是這樣的:
constructor(public formBuilder: FormBuilder,
public documentService: DocumentService,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.createForm();
if (this.data.edit) {
this.setValues();
}
this.setTitles();
}
createForm 調用會創建反應式表單,我在其中進行了異步驗證:
createForm() {
this.documentForm = this.formBuilder.group({
...
documentNumber: new FormControl('',
{
updateOn: 'blur',
validators: [Validators.required],
asyncValidators: [this.checkDocumentNumber.bind(this)]
}),
...
});
}
如果對話框處於「編輯」模式,setValues 調用會修補需要編輯的數據:
setValue() {
this.form.patchData({
...
documentNumber: this.data.document.documentNumber
...
});
}
setTitles 呼叫會設定對話方塊的標題。
呼叫 checkDocumentNumber 從伺服器取得一個 boolean 值:
checkDocumentNumber(control: AbstractControl): Observable<ValidationErrors | null> {
const formValue = this.form.value;
return this.documentService
.checkDocumentNumber(new Document(this.data.edit ? this.data.document.id : 0,
form.documentNumber)).pipe(map((response: boolean) => {
return response ? { inUse: true } : null;
}));
}
所進行的 API 調用是:
checkDocumentNumber(doc: Document) {
return this.http.post(`/Documents/Inbox/CheckDocumentNumber`, doc);
}
在「編輯」模式下,表單對話框是這樣稱呼的:
this.dialogService.open(DocumentDialogComponent,
{
data: {
edit: true,
document: this.document
}
});
我遇到的問題是,當我打開對話框來編輯文件資料時,會進行 9 次 API 調用來檢查文件編號。前 5 次被取消,然後有一次返回 200,再有一次被取消,最後還有另外兩次返回 200。
在應用程式的不同部分相同的情況下,我得到了 3 個取消和兩個 200 呼叫。
我該如何阻止 Angular 做這些不必要的 API 呼叫?在 Angular 5 之前,updateOn 標誌不存在,所以我以為沒有它,這種情況就不會發生。
這是一個正在進行的 API 呼叫的截圖:
答案#1
你可以使用 debouncePromise 函數來減少觸發次數。這可能是由於視圖的重新渲染造成的。
asyncValidators: [debouncePromise(this.checkDocumentNumber.bind(this))]
答案#2
Angular 在每次值更改時都會執行請求。文檔指定只有當同步驗證通過時才使用非同步驗證「以避免可能代價高昂的非同步驗證過程(例如 HTTP 請求)」
這是我認為正在發生的事情:
`
updateOn: 'blur'` 是針對使用者互動的設定。當你透過程式碼更改值時,它並不適用。你實例化表單 → 驗證器被觸發,進而引發請求。
你在
setValue()中使用patchData()-> 驗證器會再次被觸發。我猜 Angular 在內部對驗證 Observable 使用了 switchMap,這可以解釋如果你改變了值就會取消的情況
我不知道你是如何達到 9 個請求的,為此我需要看到完整的程式碼(如註解的 @EstusFlask,http://stackoverflow.com/help/mcve)。
可能有幫助的是:
添加一些同步驗證器。
Validators.required將避免對空值發出請求,包括初始的''與其在創建表單後單獨修補默認值,不如在創建時計算默認值。
在默認值為空且使用required的情況下不需要,但在其他情況下需要,我覺得這樣更清晰。const defaultDocumentNumber = this.data.edit ? this.data.document.documentNumber : ''; ... documentNumber: new FormControl(defaultDocumentNumber, ...我猜測你的表單中有其他控件正在觸發驗證。這可能解釋了你如何達到 9 次呼叫。
如果是這種情況,你可以使用FormControl.patchValue()的第二個參數options來避免某些驗證觸發,特別是emitEvent和onlySelf欄位。
同樣,如果沒有可重現的範例,真的無法確定。可以看看文件說明。
