form.setValues()多次触发异步验证

问题描述 投票:0回答:4

我正在使用 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 调用的屏幕截图:

angular typescript angular5
4个回答
1
投票

您可以使用 debouncePromise 函数来减少触发次数。可能是视图重新渲染导致的。

asyncValidators: [debouncePromise(this.checkDocumentNumber.bind(this))]

0
投票

Angular 在每次值更改时执行请求。仅当同步验证器通过时,文档才指定异步验证器“以避免潜在昂贵的异步验证过程(例如 HTTP 请求)”

这就是我认为正在发生的事情:

  • updateOn: 'blur'
    用于用户交互。当您通过代码更改值时,它不适用。

  • 您实例化表单 -> 验证器被触发,触发请求。

  • patchData()
    setValue()
    -> 验证器再次被触发。

  • 我猜测 Angular 内部使用 switchMap 来验证 Observable,如果你更改了值,这将解释取消的情况

我不知道你是如何得到 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
    字段来避免某些验证触发器。
    再说一次,如果没有可重现的例子,就不能真正说。查看文档


0
投票

在我们的例子中,根本问题是输入已从 DOM 中删除。 隐藏字段时,如果将其从 DOM 中删除,请务必将其从响应式表单中删除。

我们最好的猜测是,当找不到表单输入时,Angular 会不断重试 AsyncValidator。


-1
投票

正如这个答案所说,渲染可能会导致异步验证上的多个触发器,我遇到了同样的问题,并使用

debounceTime(1)
来避免它帮助我解决它。

© www.soinside.com 2019 - 2024. All rights reserved.