Angular 响应式表单 - 订阅表单数组中的表单控件实例以获取总值
Angular Reactive Form - Subscribe to instances of Form Control in Form Array to get total value
我正在使用 Angular 响应式表单遍历值数组我希望在表单数组之后有一个总字段,该字段根据表单数组控件值的变化进行更新。
示例数据:
primaryData = {
products: [
{
name: 'test-product',
unmoved: 21,
moved: 18
},
{
name: 'another-product',
unmoved: 18,
moved: 42
}
]
}
我正在创建响应式表单控件和数组,如下所示:
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();
}
让我的 unmovedTotal
和 movedTotal
控件根据 Array 控件中的更改进行更新的最佳方法是什么。这是一个 StackBlitz 演示我的结构。
在我看来,您要查找的总数不应该出现在表格中。它在您的 Typescript 中被无条件禁用,我想不出您可以直接编辑总计的用例。它只是一个不合形式的计算值。
也就是说,有一个类型的可观察对象是件好事:
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
运算符。
在表单上,我们要遍历数量并为 moved
和 unmoved
属性生成总和。所以在这里我们不能使用 map
(基本的 JS 映射,而不是来自 RXJS 的映射),因为它会产生一个数组。为此,我们可以使用 reduce
(再次来自纯 JS,这里没有 RXJS)。
现在我们已经有了我们的可观察对象,我们只需要在视图中使用它。为了避免两次订阅,我们可以使用 ngIf
和 as
语法:
<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
我正在使用 Angular 响应式表单遍历值数组我希望在表单数组之后有一个总字段,该字段根据表单数组控件值的变化进行更新。
示例数据:
primaryData = {
products: [
{
name: 'test-product',
unmoved: 21,
moved: 18
},
{
name: 'another-product',
unmoved: 18,
moved: 42
}
]
}
我正在创建响应式表单控件和数组,如下所示:
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();
}
让我的 unmovedTotal
和 movedTotal
控件根据 Array 控件中的更改进行更新的最佳方法是什么。这是一个 StackBlitz 演示我的结构。
在我看来,您要查找的总数不应该出现在表格中。它在您的 Typescript 中被无条件禁用,我想不出您可以直接编辑总计的用例。它只是一个不合形式的计算值。
也就是说,有一个类型的可观察对象是件好事:
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
运算符。
在表单上,我们要遍历数量并为 moved
和 unmoved
属性生成总和。所以在这里我们不能使用 map
(基本的 JS 映射,而不是来自 RXJS 的映射),因为它会产生一个数组。为此,我们可以使用 reduce
(再次来自纯 JS,这里没有 RXJS)。
现在我们已经有了我们的可观察对象,我们只需要在视图中使用它。为了避免两次订阅,我们可以使用 ngIf
和 as
语法:
<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