Angular Reactive Form - Подпишитесь на экземпляры Form Control в массиве Form, чтобы получить общую стоимость
Я использую Angular Reactive Forms для перебора массива значений. Я хотел бы иметь итоговое поле после массива форм, которое обновляет изменения значений элемента управления массива форм.
Пример данных:
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();
}
Какой лучший способ получить мой unmovedTotal
а также movedTotal
Обновление элементов управления на основе изменений в элементах управления Array. Вот StackBlitz, демонстрирующий мою структуру.
1 ответ
Итоги, которые вы ищете, не должны быть в форме, по моему мнению. Он отключен без каких-либо условий в вашем 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