对表单数组中的表单控件求和 angular

Sum form Controls in form Array angular

我有我的反应形式,看起来像这样

<form [formGroup]="addInvoiceForm" (submit)="onAddInvoiceFormSubmit()">
  <div [formArrayName]="itemRows">
    <div *ngFor="let itemrow of addInvoiceForm.controls.itemRows.controls; let i=index" [formGroupName]="i">
      <input autocomplete="off" type="text" formControlName="itemqty">
      <input autocomplete="off" type="text" formControlName="itemrate">

      <!-- the input field below is to be summed -->
      <input autocomplete="off" type="text" formControlName="itemamt" [ngModel]="itemrow.get('itemqty').value * itemrow.get('itemrate').value">

    </div>
  </div>
  <button type="button" (click)="addItemRow()">Add New Row</button>
</form>

我想对用户创建的所有行的项目求和并将它们传递到表单数据中。谁能帮我,告诉我如何对表单中的所有项目字段求和并并排显示用户总金额是多少?

求和逻辑最好在组件 class 中,而不是在 HTML 中。您可以使用返回总和的 getter 定义 属性。

一般来说,语法是这样的:

get sum():number {
    let summed = 0;
    for (var key in sample) {
        summed += sample[key];
    };
    return summed; 
} 

注意:您也可以使用 Array.prototype.reduce(),但上面的语法更直接。

此外,考虑使用 ngSubmit 而不是提交。

如果您想在提交 post 请求之前对所有值求和,您可以这样做。

在您的提交请求中传递表单值

<form [formGroup]="addInvoiceForm" novalidate (submit)="onAddInvoiceFormSubmit(addInvoiceForm.value)">

</form>

在组件文件中。

您将拥有更新的表单对象。只需迭代 addInvoiceForm.itemRows 并创建 sum.

onAddInvoiceFormSubmit(addInvoiceForm){
// you will have update form object. just iterate the addInvoiceForm.itemRows and create sum.

}

注意:-在启用提交按钮之前进行所有验证

我想知道是否有更好的方法,但我尝试使用 getter,它抱怨 Expression has changed... 尝试将 ChangeDetectorRef 添加到混音中导致无限循环。

所以我决定在表单数组中监听 valueChanges,我还需要在其中使用 ChangeDetectorRef,所以首先导入它并将其注入到您的构造函数中:

import { ChangeDetectorRef } from '@angular/core';

constructor(private fb: FormBuilder, private ref: ChangeDetectorRef) { }

然后 valueChanges:

// subscribe to changes in the formArray
this.invoiceForm.get('itemRows').valueChanges.subscribe(values => {
  // reset the total amount  
  this.summed = 0;
  const ctrl = <FormArray>this.invoiceForm.controls['itemRows'];
    // iterate each object in the form array
    ctrl.controls.forEach(x => {
      // get the itemmt value and need to parse the input to number
      let parsed = parseInt(x.get('itemamt').value)
      // add to total
      this.summed += parsed
      this.ref.detectChanges()
    });
  }) 

为了构建您的表单,您需要添加一个新的表单控件,因为您希望它成为表单的一部分:

this.invoiceForm = this.fb.group({
  itemRows: this.fb.array([this.initItemRows()])
  summed: [null] // here
}); 

在您的模板中:

<input readonly [ngModel]="summed" formControlName="summed" />

Demo


编辑:

我建议你使用我们的好yurzui建议的解决方案,比我的解决方案优雅得多,所以在valueChanges里面使用reduce()

resolvedPromise.then(() => {
  this.summed = values.reduce((acc, cur) => acc + cur.itemamt, 0);
});

和变量:

const resolvedPromise = Promise.resolve(null);

yurzui 建议的回答

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';

const resolvedPromise = Promise.resolve(null);

@Component({
  selector: 'my-app',
  template: ...
})


export class App implements OnInit {
    public invoiceForm: FormGroup;
    summed: number;

    constructor(private fb: FormBuilder, private ref: ChangeDetectorRef) {}
    
    ngOnInit(){
        this.invoiceForm = this.fb.group({
          itemRows: this.fb.array([this.initItemRows(), this.initItemRows()])
        });
        
        this.invoiceForm.get('itemRows').valueChanges.subscribe(values => {
          resolvedPromise.then(() => {
            this.summed = values.reduce((acc, cur) => acc + cur.itemamt, 0);
          });
        })
    }
}