角度反应表单 - 在表单数组中订阅表单控件的实例以获得总值

时间:2018-05-21 18:00:55

标签: angular typescript subscription angular-reactive-forms formarray

我正在使用Angular Reactive Forms迭代一个值数组,我希望在Form Array之后有一个total字段,用于更新Form Array控件值的更改。

示例数据:

  primaryData = {
    products: [
      {
        name: 'test-product',
        unmoved: 21,
        moved: 18 
      },
      {
        name: 'another-product',
        unmoved: 18,
        moved: 42
      }
    ]
  }

我正在创建Reactive Form Controls和Array,如下所示:

  setPrimaryQuantities() {
    const control = <FormArray>this.primaryForm.controls.quantities;
    this.primaryData.products.forEach(product =>
      control.push(this.fb.group({
        name: [product.name, Validators.required],
        unmoved: [product.unmoved, Validators.required],
        moved: [product.moved, Validators.required]
      }))
    )
  }

  ngOnInit() {
    this.primaryForm = this.fb.group({
      quantities: this.fb.array([]),
      unmovedTotal: '',
      movedTotal: ''
    })
    this.setPrimaryQuantities();
  }

根据Array控件中的更改,让unmovedTotalmovedTotal控件更新的最佳方法是什么。这是展示我结构的StackBlitz

1 个答案:

答案 0 :(得分:3)

在我看来,您所寻找的总数不应该在表格中。它在您的打字稿中没有任何条件而被禁用,我无法想到您直接编辑总计的用例。它只是表格中的计算值。

那说,一个好处是有一个可观察的类型:

total$: Observable<{ moved: number, unmoved: number }>

要做到这一点,因为你已经使用了被动形式,它非常直接:)

this.total$ = this.primaryForm.valueChanges.pipe(
  startWith(this.primaryForm.value),
  map(f => f.quantities.reduce(
    (acc, q) =>
    ({
      moved: acc.moved + q.moved,
      unmoved: acc.unmoved + q.unmoved
    }),
    { moved: 0, unmoved: 0 }
  ))
);

每次表单更改时,您都希望获得新的总计。如果要从初始值(表单的值)中生成新值(总计),请使用map运算符。

在表单上,​​我们希望循环数量并为movedunmoved属性生成总和。所以在这里我们不能使用map(基本的JS地图,而不是RXJS中的地图)因为它会产生一个数组。为此,我们可以使用reduce(再一次来自纯JS,没有RXJS)。

现在我们已经获得了可观察性,我们只需要将它用于视图中。为了避免两次订阅,我们可以将ngIfas语法结合使用:

<tr *ngIf="total$ | async as total">
  <td>Totals</td>
  <td>{{ total.unmoved }}</td>
  <td>{{ total.moved }}</td>
</tr>

以下是基于您最初的Stackblitz示例的完整示例:

https://stackblitz.com/edit/angular-kbk3zm?file=src%2Fapp%2Fapp.component.ts