使用 Angular FormArray 计算的值
Calculated values using Angular FormArray
我正在尝试根据 FormArray 中的特定值计算总值或其他值。
我发现当订阅 valueChanges
并尝试将整个数组传递给 reduce
之类的东西时,"new value" 不在父 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 还很陌生,所以我确定我只是遗漏了一些基本知识。
UPDATE(有解决办法,但还是不懂):
我真的很想知道为什么我不能像 Eliseo 建议的那样订阅整个数组的更改。
我也很想知道为什么我使用 .value
的地方会有这么大的差异 - 如果 Reactive Forms 的全部要点是模型驱动然后将 frm.value
传递给你的提交函数,那么为什么 .value
在整个表单层次结构中如此不一致?
更新 2
Updated StackBlitz Solution with guidance from Eliseo after his update
我找到了一个我觉得很不错的解决方案。它没有在任何地方使用 controls
并且感觉非常干净。 Eliseo 建议的方法促使我尝试这个。我认为重要的是转换为 FormArray
并在其上执行任何 push
。这使 parent
字段与 FormGroup
或 FormArray
的其余部分相关联,因此它仍包含在 valueChanges
事件中。
我现在认为使用 controls
是 Angular 响应式表单的反模式,但我需要搜索有关该主题的更多指导。
我成功了。
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 的代码:
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 的方式。
我正在尝试根据 FormArray 中的特定值计算总值或其他值。
我发现当订阅 valueChanges
并尝试将整个数组传递给 reduce
之类的东西时,"new value" 不在父 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 还很陌生,所以我确定我只是遗漏了一些基本知识。
UPDATE(有解决办法,但还是不懂):
我真的很想知道为什么我不能像 Eliseo 建议的那样订阅整个数组的更改。
我也很想知道为什么我使用 .value
的地方会有这么大的差异 - 如果 Reactive Forms 的全部要点是模型驱动然后将 frm.value
传递给你的提交函数,那么为什么 .value
在整个表单层次结构中如此不一致?
更新 2
Updated StackBlitz Solution with guidance from Eliseo after his update
我找到了一个我觉得很不错的解决方案。它没有在任何地方使用 controls
并且感觉非常干净。 Eliseo 建议的方法促使我尝试这个。我认为重要的是转换为 FormArray
并在其上执行任何 push
。这使 parent
字段与 FormGroup
或 FormArray
的其余部分相关联,因此它仍包含在 valueChanges
事件中。
我现在认为使用 controls
是 Angular 响应式表单的反模式,但我需要搜索有关该主题的更多指导。
我成功了。
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 的代码:
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 的方式。