Sum form控件的形式Array angular

时间:2017-05-10 15:09:41

标签: angular reactive-forms

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

<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>

我想总结用户创建的所有行的itemamt并将它们传递给表单数据。有人可以帮助我,告诉我如何将表格中的所有itemamt字段相加并并排显示用户的总金额是什么?

4 个答案:

答案 0 :(得分:4)

我想知道是否有更好的方法,但我尝试使用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);

答案 1 :(得分:0)

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

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

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

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

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

答案 2 :(得分:0)

如果你想在提交帖子请求之前加总所有值,你可以这样做。

在提交请求中传递表单值

<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.

}

注意: - 在启用提交按钮

之前执行所有验证

答案 3 :(得分:0)

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