使用Angular FormArray

时间:2018-02-27 23:33:06

标签: angular typescript angular-reactive-forms formarray

我试图根据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的重点是模型驱动,然后将frm.value传递给你的提交函数,那么为什么.value在整个表单层次结构中如此不一致?

更新2

Updated StackBlitz Solution with guidance from Eliseo after his update

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

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

2 个答案:

答案 0 :(得分: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)
  });

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

答案 1 :(得分: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的制作方式。