4

我正在尝试根据 FormArray 中的特定值计算总值或其他值。

我发现当订阅valueChanges并尝试将整个数组传递给类似reduce的东西时,父 FormGroup 上不存在“新值”。

StackBlitz 上的原始示例

样本:

this.frm.get('arr')['controls'][i].valueChanges
  .subscribe((newVal) => {
    this.frm.get('total').patchValue(
      this.frm.get('arr').value.reduce((acc, curr) => {
        return acc + curr.v;
      }, 0)
    )
  });

如果arr有值[0, 1, 2, 3, 4]并且我将第一个值更改为1,我仍然得到10而不是11

this.frm.get('arr').value显示所有初始值而不是更新值。

我对 Reactive Forms 还很陌生,所以我确定我只是在这里遗漏了一些基本的东西。

更新(有一个解决方案,但我仍然缺乏理解):

我真的很想知道为什么我不能像 Eliseo 建议的那样订阅对整个数组的更改。

我也对为什么我使用的地方之间存在如此大的差异感兴趣.value- 如果反应式表单的全部要点是模型驱动然后传递frm.value给您的提交函数,那么为什么.value整个表单层次结构如此不一致?

更新 2

在 Eliseo 更新后的指导下更新了 StackBlitz 解决方案

我找到了一个我感觉很好的解决方案。它没有controls在任何地方使用,感觉非常干净。Eliseo 建议的方法促使我尝试这样做。我相信重要的是铸造 aFormArray并在其上执行任何push。这使该parent字段与您的其余部分保持联系FormGroupFormArray因此它仍然包含在valueChanges事件中。

我现在相信 usingcontrols是 Angular Reactive Forms 的反模式,但我需要寻找关于该主题的更多指导。

4

2 回答 2

4

我得到了这个工作。

this.frm.get('arr')['controls'][i].valueChanges
  .subscribe((newVal) => {
    this.frm.get('total').patchValue(
      this.frm.get('arr').value.reduce((acc, curr) => {
        return acc + curr.v;
      }, 0) + (+newVal.v)
    )
  });

你的表格有些奇怪。所有 5 个控件都绑定到同一个formControlName“v”。我认为这可能是此表格未按您希望的方式运行的原因。以上确实有效,但是newVal像这样在最后添加似乎很奇怪。

更新:

这适用于所有字段更改。

this.frm.get('arr')['controls'][i].valueChanges
  .subscribe((newVal) => {
      const arr = <FormArray>this.frm.controls['arr'];
      let total = 0;
      arr.controls.forEach((c: any) => {
        console.log(c.value);
        total+= +c.value.v;
      });
      console.log('total',total);
      this.frm.get('total').patchValue(total)
  });

不是我见过的最漂亮的代码,但它确实有效。摆脱控制台日志,它可能是你可以忍受的。:)

于 2018-02-28T00:23:59.230 回答
2

为什么不听所有数组的变化并用 newValues 合计?

 //NOT ['controls'][i]
this.frm.get('arr')['controls'].valueChanges
  .subscribe((newVal) => {
    this.frm.get('total').patchValue(
      //use newVal
      newVal.reduce((acc, curr) => {
        return acc + curr.v;
      }, 0)
    )
  });

那是行不通的,为此更改 buildForm 的代码:

buildForm() {
    let controls:any[]=[];
    for (let i:number = 0; i < 5; ++i) {
      controls.push(this.builder.group({
        v: i
      }))
    this.frm = this.builder.group({
      total: [{value: '', disabled: true}],
      arr: this.builder.array(controls)
    });
      this.frm.get('arr').valueChanges
      .subscribe((newVal) => {
        let total:number=0;
        newVal.forEach(e=>{
          total=total+parseInt(e.v)});

        this.frm.get('total').patchValue(total,0)

      });
    }
  }

主要变化是使用 forEach 而不是 reduce,使用 parseInt,以及制作 formArray 的方式。

于 2018-02-28T08:53:18.493 回答