Angular响应式Form Array如何计算ItemTotal单项总价与发票总金额
Angular响应式表单实现药品采购金额计算方案
单项金额ItemTotal计算
每个药品行的itemTotal = quantity * unitPrice,需要在新增药品行时监听该行的数量、单价字段变化,实时计算赋值:
- 新增药品行时为对应表单组添加值变化订阅
- 空值兜底处理,避免数值为空时出现NaN结果
- 金额保留两位小数避免浮点误差
总金额subtotal计算
监听整个药品列表FormArray的数值变化,累加所有行的itemTotal得到总金额,赋值给表单的subtotal字段。
完整修改代码
import { takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; medicinePurchaseForm: FormGroup; // 用于销毁订阅,避免内存泄漏 private destroy$ = new Subject<void>(); ngOnInit(): void { this.initForm(); // 初始化后监听药品列表变化,自动计算总金额 this.watchSubtotalChange(); } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } private initForm() { this.medicinePurchaseForm = new FormGroup({ prescriptionId: new FormControl(), subtotal: new FormControl(0), purchaseMedicineList: new FormArray([]) }); } get medicineArray() { return this.medicinePurchaseForm.controls.purchaseMedicineList as FormArray; } addMedicinetoLine(){ const purchasemedicine = new FormGroup({ medicineId: new FormControl(this.medicineID.value, Validators.required), medicineName: new FormControl(this.brandName.value, Validators.required), unitPrice: new FormControl(this.price.value || 0), quantity: new FormControl(this.quantity.value || 0, Validators.required), itemTotal: new FormControl(0), }); // 监听当前行单价、数量变化,计算单项金额 purchasemedicine.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe(value => { const price = Number(value.unitPrice) || 0; const count = Number(value.quantity) || 0; const total = +(price * count).toFixed(2); purchasemedicine.get('itemTotal').setValue(total, { emitEvent: false }); }); this.medicineArray.push(purchasemedicine); // 新增行后手动触发一次总金额计算 this.calcSubtotal(); } // 监听药品列表变化,自动计算总金额 private watchSubtotalChange() { this.medicineArray.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe(() => { this.calcSubtotal(); }); } // 计算总金额逻辑 private calcSubtotal() { const total = this.medicineArray.controls.reduce((sum, item) => { return sum + (Number(item.get('itemTotal').value) || 0); }, 0); this.medicinePurchaseForm.get('subtotal').setValue(+(total).toFixed(2), { emitEvent: false }); }
注意事项
- 所有金额字段初始化默认值为0,避免空值导致计算异常
- 计算时使用
toFixed(2)保留两位小数,前端金额计算如果要求高精度可以替换为decimal.js等精度计算库 - 使用takeUntil配合destroy$销毁订阅,避免组件销毁后内存泄漏
- setValue时添加
emitEvent: false避免触发重复的valueChanges事件,减少不必要的计算
内容的提问来源于stack exchange,提问作者MD SHAFFAT
相关产品推荐
相关产品推荐

