使用Angular FormArray计算的值

问题描述 投票:2回答:2

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

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

Original Example on 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的地方之间存在这样的差异 - 如果Reactive Forms的整个点是Model Driven然后将frm.value传递给你的Submit函数,那么为什么.value在整个表单层次结构中如此不一致?

更新2

Updated StackBlitz Solution with guidance from Eliseo after his update

我找到了一个我觉得很好的解决方案。它没有在任何地方使用controls,感觉非常干净。 Eliseo的建议方法促使我尝试这一点。我相信重要的是投射到FormArray并执行任何push。这使得parent场与你的FormGroupFormArray的其余部分相关联,因此它仍然包含在valueChanges事件中。

我现在相信使用controls是Angular Reactive Forms的反模式,但我需要搜索有关该主题的更多指导。

angular typescript angular-reactive-forms formarray
2个回答
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,以及makeArray的制作方式。


3
投票

我得到了这个工作。

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)
  });

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

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