You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular响应式Form Array如何计算ItemTotal单项总价与发票总金额

Angular响应式表单实现药品采购金额计算方案

单项金额ItemTotal计算

每个药品行的itemTotal = quantity * unitPrice,需要在新增药品行时监听该行的数量、单价字段变化,实时计算赋值:

  1. 新增药品行时为对应表单组添加值变化订阅
  2. 空值兜底处理,避免数值为空时出现NaN结果
  3. 金额保留两位小数避免浮点误差

总金额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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 05:18:02