【问题标题】:How does change detection on control work when form is patched?修补表单时,控件上的更改检测如何工作?
【发布时间】:2020-12-27 14:38:14
【问题描述】:

我想知道以下情况会发生什么:

我有一个带有这些控件的 formGroup:

{
  forename: new FormControl()
  surname: new FormControl()
}

现在我像这样跟踪控件“姓氏”的变化(只是一个例子):

this.formGroup.get('surname').valueChanges.subscribe(changes => {
   if(this.formGroup.get('forename') == 'Max'){
      this.formGroup.get('forename').disable();
   }
})

最后我正在像这样修补我的表单:

this.formGroup.patchForm({surname: 'Muster', forename: 'Max'});

会禁用“名字”控件吗?因为我不确定它是否会在设置控件“名字”的值之前触发控件“姓氏”的更改。因此,“forename”可能还没有“正确”的值。

我试图更好地理解,当触发确切的 valueChanges 事件时,因为我有时会遇到问题,即未设置值,尽管它们应该设置。

我还想知道是否可以等到每个控件都被修补后再发出更改。

【问题讨论】:

  • 在整个表单对象上尝试valueChanges。如果表单上的任何值发生更改,这将触发,然后您可以使用 filter 运算符过滤类型。类似this.form.valueChanges.filter(x => x).subscribe(...)
  • 不知道如何为更大的表格做到这一点。我可以做this.formGroup.valueChanges.subscribe(changes =>....),这会给我一个包含所有变化的对象,但是我必须将它与现有对象进行比较以确定实际发生了什么变化?我可能有 20 多个控件,所以这似乎不是一个好的解决方案。不知道我应该如何“过滤”它,因为没有像 filter-Function 这样的东西。
  • 如果我将更新对象中的道具顺序更改为:{ forname: 'Max', surname: 'Muster' },那么一切似乎都按预期工作。

标签: angular angular-reactive-forms angular-changedetection


【解决方案1】:

原因:

surnamevalueChanges 将在patchValue() 更新第一个属性时立即触发,因此您将获得null 作为forename 的值,而条件this.formGroup.get('forename') == 'Max' 将是false

解决方案 1:

您可以subscribe()valueChanges 的整个formGroup 而不是单个控件,然后检查所需的条件。像这样:

this.formGroup
      .valueChanges // subscribe to all changes
      .pipe(
        filter(form => form.forename === 'Max') // check if 'forname' is 'Max'
      ).subscribe(
        forename => this.formGroup.get('forename').disable() // disable control
      );

解决方案 2:

您只需更改要更新的对象中道具的顺序即可使用您的代码获得所需的行为。像这样:

this.formGroup.patchForm({ forename: 'Max', surname: 'Muster' });

Working Demo with Solution 1

【讨论】:

  • 您好,感谢您的解释!我实际上考虑使用解决方案 2,但我不想仅仅因为对象中的属性没有特定的顺序而遇到错误。解决方案 1 也很有趣!最后我决定基本上在名字上放另一个 valueChanges-Subscription (我将回答我自己的问题来演示)。这可能不是最干净的,但对于我的项目,它不是重建所有 valueChanges 事件以匹配类似于第一个解决方案的选项。
【解决方案2】:

这就是我最终做的:

this.formGroup.get('surname').valueChanges.subscribe(changes => {
   this.handleForenameControl();
})

this.formGroup.get('forename').valueChanges.subscribe(changes => {
   this.handleForenameControl();
})

private handleForenameControl():void{
  if(this.formGroup.get('forename') == 'Max'){
      this.formGroup.get('forename').disable();
   }
}

我知道这不是最干净的,我正在考虑不放另一个 valueChanges-Subscription,但是是的。

我的意思是上面只是一个例子,没有我在项目中实际使用的代码,所以这个例子可能很糟糕。也许这仍然可以帮助某人。

【讨论】:

  • 这和答案的解决方案1不一样吗?我的意思是,订阅更改所有形式的值还是单独订阅更改所有值?至少在这种情况下,控件只有 2 个。是的,它不是最干净的方式,但如果它适合你而不是实际项目的一部分,那么我想它很好:)
  • 最后,如果您能解释一下为什么不使用解决方案 1,那么我可以根据需要对其进行更新。
猜你喜欢
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
  • 1970-01-01
  • 2016-04-25
  • 2011-11-15
  • 2021-03-08
相关资源
最近更新 更多