使用{ emitEvent: false }进行patchValue会在Angular 4的formgroup上触发valueChanges。

60

我有一个表单构建组,监听valueChanges事件并触发保存函数,然后在表单上刷新:

 this.ticketForm.valueChanges.debounceTime(1000).distinctUntilChanged()
 .subscribe(data => {
   this.saveTicket();
   this.refreshTicket();
 })

我随后重新加载表单,并使用patchValue将数据重新填充到表单字段(以及页面上的其他位置,特别是更改日志)中,例如:

    this.ticketForm.patchValue(ticket, { emitEvent: false });

然而,尽管设置 emitEvent : false,这会导致表单无限保存循环。

这是Angular 4/Ionic 3的bug还是我自己的误解?


2
补丁值的更改不会触发变化事件,因此valueChanges无法检测到。 - larpo
8
我也一样,你找到答案了吗? - Reza
3
使用 Angular 5 中的 patchValue(value, {emitEvent: false}) 方法时,不会触发事件。 - Amiram Korach
5
我也在使用Angular 6,仍然使用emitEvent:false进行触发...这不是每个人都会发生的吗? - Methodician
8
我曾遇到同样的问题,后来发现是因为我在使用自定义表单控件(customFormControl)时,在初始化时没有考虑到 emitEvent: false。 - Tonio
显示剩余9条评论
7个回答

50
尝试添加以下内容:onlySelf: true,并与emitEvent: false一起使用,如下所示:
this.ticketForm.patchValue(ticket, {emitEvent: false, onlySelf: true});

31
不确定这对原帖作者有没有用,但对我没有起作用。 - Craig Wayne
这对我有用。像这样进行修改, this.ticketform.updateValueAndValidity({emitEvent: false, onlySelf: true}) - Pradeep shyam
3
可能是一个错误。根据文档,它说只有self应该默认为true,这不应该产生影响。无论如何,在这里的行为都不符合文档中预期的行为。 - Jared G
我只使用了emitEvent的setValue,它对我起作用了,谢谢! - Khuram Niaz
我尝试了上面的解决方案,它对我也起作用。然而,Pradeep的评论让我感到困惑。我希望没有副作用。 - mtnp
在13.0.2版本中,它对我不起作用。当启用先前禁用的控件时,它可以工作。this.formGroup.controls['samplingTime'].enable({emitEvent: false})。但是使用setValue/reset时无法正常工作this.formGroup.get('samplingTime').reset(new Date(), {emitEvent: false, onlySelf: true});我正在使用Subscribe()。 - Norbert Norbertson

9

由于声望限制,我无法进行评论,因此我将其作为对 @Craig Wayne 的答案发布。

仅当您使用以下方式监听表单控件的值更改时,emitEvent:false 才起作用:

this.form.valueChanges.controlName.subscribe(val => doSomething(val));

如果您绑定了元素的模型更改,无论如何都会触发事件:

<input (ngModelChange)="doSomething($event)"/>

8

在使用Angular 9.1.13时,我遇到了同样的问题。 尝试使用FormControl.setValueFormGroup.patchValue API,并在所有可能的组合中使用建议的参数{emitEvent: false, onlySelf: true}。 但是valueChanges可观察对象仍然会被触发。

最终对我有用的唯一方法是:

myForm.disable();
myForm.patchValue({myControl: ''}, {onlySelf: true, emitEvent: false});
myForm.enable();

1
我的项目是基于Angular 8.3.21的,这是唯一对我有效的答案。感谢@ktsangop。 - gslette
2
我的项目是基于 Angular 13 的,但即使如此也没有起作用。 - Victor Zakharov
作为最后的尝试,我会尝试将 patchValue 和/或 enable 调用包装在 setTimeout(...) 中。虽然不太优雅,但谁知道呢... - ktsangop
我刚刚围绕标准的valueChanges和rxjs创建了自己的框架/库,它可以设置一个布尔变量,从而相应地改变行为。 - Victor Zakharov
2
@VictorZakharov 请开源吧! - Meqwz

1
为什么在值改变时要使用 patchValue,而不是在 onInit 时设置它?
个人而言,在构建两个必填的 FormControl 之间选择时,我在不同的上下文中遇到了此问题。
我让一个字段清空另一个字段(按设计,只有一个应该填写),但是 then the subscribe triggered the original to clear. 因为我需要我的验证器在更新时运行,所以 emitEvent:false 没有帮助。添加 if(value) 可以帮助避免级联修补。见下文:
this.formGroup.controls.item1.valueChanges.subscribe(value => {
   if(value){
     this.formGroup.patchValue({
       'item2':null
     })
   }
})

this.formGroup.controls.item2.valueChanges.subscribe(value => {
   if(value){
     this.formGroup.patchValue({
       'item1':null
     })
   }
})

注意:为了简单起见,我没有包括 .pipe(takeUnitl(this.destroy$))。如果您不包括它,它会导致内存泄漏。

1
我建议在回答中不要使用修辞性问题。它们可能会被误解为根本不是答案。你是在尝试回答这个页面顶部的问题,对吗?否则请删除此帖子。 - Yunnosch

0

对于我在 Angular 15 中使用的问题,没有任何提出的解决方案适用...

我正在使用 ngModelChange 事件监听器。


0
没有一个答案对我有用,我不得不手动操作:
首先,在类中定义一个布尔变量:
private dontAllowChangeEventFromForm = false;

然后我定义了以下函数,使用rxjs的pipe和filter。
private getControlValueChangesWithRestrictions(control: AbstractControl): Observable<any> {
  return control.valueChanges.pipe(
    filter(_ => !this.dontAllowChangeEventFromForm)
  );
}

然后听取变化使用

this.getControlValueChangesWithRestrictions(this.form).subscribe()

现在每当我想要静默更新表单时,我就这样做
this.dontAllowChangeEventFromForm = true;
this.form.patchValue(/*patch value*/)
this.dontAllowChangeEventFromForm = false;

-1
作为一种解决方法,我在 RxJS 的管道中添加了 skip。
this.form.valueChanges
    .pipe(skip(1)).subscribe();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接