使用 Angular FormArray 计算值



>我正在尝试根据 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显示所有初始值,而不是更新的值。

我对反应式表单相当陌生,所以我确定我只是在这里错过了一些基本的东西。

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

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

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

更新 2

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

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

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

我让它工作了。

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

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

为什么不监听所有数组的变化并使用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() {
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)
});
}
}

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

相关内容

  • 没有找到相关文章

最新更新