【问题标题】:Stop infinite loop reactive forms control update in Angular停止 Angular 中的无限循环反应形式控件更新
【发布时间】:2026-01-18 08:15:01
【问题描述】:

我在一个表单上有 2 个输入,一个名为“ageMonths”的数字输入和一个名为“dateOfBirth”的日期选择器。

我希望用户能够输入年龄的月份,或使用日期选择器选择出生日期 (dob)。如果他们从日期选择器输入一个 dob,我希望月份字段更新为以月为单位的年龄。如果他们以月为单位输入年龄,我希望日期选择器跳转到该日期。我正在使用响应式表单。

我添加了一个类级别变量来保存一个切换,该切换在每次任一控件的值更改时读取和设置。但这并没有按预期工作,我认为是由于事件未按我期望的顺序触发。

我需要做什么才能完成这项工作?

我的代码是:

ignoreDateUpdate = false;
form: FormGroup;
...
constructor(...){
this.form = new FormGroup({
    dateOfBirth: new FormControl({ value: new Date()}),
    ageMonths: new FormControl({ value: 0 }),
    ...
});
...
this.form.get('ageMonths').valueChanges.subscribe(
m => {
    if (ignoreDateUpdates) {return};
    ignoreDateUpdates = true;
    <code to set DateSelectorValue>
    ignoreDateUpdates = false;
    });
this.form.get('dateOfBirth').valueChanges.subscribe(
dob => {
    if (ignoreDateUpdates) {return};
    ignoreDateUpdates = true;
    <code to set MonthsInput>
    ignoreDateUpdates = false;
});
}

【问题讨论】:

    标签: angular rxjs angular-reactive-forms


    【解决方案1】:

    我正在回答这个问题,因为我通过在 setValue 调用中添加 {emitEvent: false} 选项来获得所需的行为:

    const calcDate = <calculate date from months value>;
    this.form.get('dateOfBirth').setValue(calcDate, { emitEvent: false });
    

    但是如果有人能解释一下,我仍然想知道为什么切换字段没有按预期工作?

    【讨论】:

    • 这帮助我找到了我需要的与此相关的内容......特别是从返回调用到更新函数的更新数据。有时您需要在表单模型中获取新数据,但不希望它触发valueChanges,否则更新循环。对我来说,使用 this.formRef.form.patchValue(someObject, { emitEvent: false }) 是神奇的调味汁!
    【解决方案2】:

    您在错误的时间将标志设置为 false,因此它什么也不做。您将其设置为 true,然后几乎立即设置为 false。当第二个表单控件发生值变化时,它总是为假。

    执行此操作(对于两个控件):

    this.form.get('dateOfBirth').valueChanges.subscribe(
      dob => {
          if (ignoreDateUpdates) {
            ignoreDateUpdates = false;
            return;
          };
          ignoreDateUpdates = true;
          <code to set MonthsInput>
      });
    

    【讨论】:

      【解决方案3】:

      我还在我的应用程序中实现了这种功能,我有两个输入框,一个是小时,第二个是分钟,每当用户以小时为单位输入值时,然后我将小时转换为分钟并更新分钟输入框,当用户以分钟为单位输入分钟时输入框然后我将分钟转换为小时并更新小时输入框。

      private  ignoreDateUpdates=true;        
      this.form.get('ageMonths').valueChanges.subscribe(m => {
              if (ignoreDateUpdates) {
              ignoreDateUpdates = false;
              <code to set DateSelectorValue>
               }
              else{
            ignoreDateUpdates = true;
               }       
       });
          this.form.get('dateOfBirth').valueChanges.subscribe(
          dob => {
              if (ignoreDateUpdates) {
              ignoreDateUpdates = false;
              <code to set MonthsInput>
             }
              else{
              ignoreDateUpdates = true;
            }    
      });
          }
      

      【讨论】:

        最近更新 更多