網站搜尋

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 欄位。
    同樣,如果沒有可重現的範例,真的無法確定。可以看看文件說明。