Создавая форму с контролем, значение относится к другим значениям управления, я заметил, что это довольно легко использовать комбинация
Оператор от RXJS. Я слушаю только для данного контроля по имена. Кроме того, я могу установить исходные значения для каждого из них.
Причина
Я работал над угловым пользовательским контролем, который содержал другие элементы управления. Особенность, которую мне нужно было рассчитать значение для одного из элементов управления на основе других элементов управления. Вот как я это решил.
Установить потоки
Я хочу рассчитать значение только тогда, когда были изменены определенные элементы управления, поэтому я устанавливаю массив с именем элементов управления и запуска.
const nameWithStarters = [ { name: 'quantityKR', value: 0 }, { name: 'quantity', value: 0 }, { name: 'priceKR', value: 0 }, { name: 'hbtPercentage', value: 100 }, ]; const valueChangers$ = nameWithStarters.map(({ name, value }) => this.form.get(name).valueChanges.pipe(startWith(value)) );
И я слушаю изменения, используя Имя
Для управления выбором и значением для начального значения. начало
Оператор От RXJS гарантирует, что каждый из моих контролей будет иметь значение по подписке.
Расчет
Чтобы вызвать расчет, я использую комбинация
функция . Он излучает, когда любой из данных потоков испускает и пропускает значения для моего простого Калькулятетоталкр
функция. В конце концов, он устанавливает значение для моего контроля вашего результата. Я добавляю его к моему Подписка
Используя Добавить
Способ иметь возможность отписаться, когда компонент разрушен (избегая утечек памяти).
const sub = combineLatest(valueChangers$) .pipe(map((values: ValuesTuple) => calculateTotalKr(values))) .subscribe(value => { this.form.get('totalKR').setValue(value); }); this.subscription.add(sub);
Полный код
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, } from '@angular/core'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR, } from '@angular/forms'; import { map, startWith } from 'rxjs/operators'; import { Benefit } from 'src/app/models/benefit'; import { combineLatest, Subscription } from 'rxjs'; type ValuesTuple = [number, number, number, number]; @Component({ selector: '[app-lines-table-row]', templateUrl: './lines-table-row.component.html', styleUrls: ['./lines-table-row.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: LinesTableRowComponent, }, ], }) export class LinesTableRowComponent implements ControlValueAccessor, OnInit, OnDestroy { @Input() benefitList: Benefit[] = []; @Output() benefitRemove = new EventEmitter(); form = this.formBuilder.group({ date: [null], type: [null], performance: [null], performanceName: [null], quantity: [null], quantityKR: [null], priceKR: [null], hbtPercentage: [100], totalKR: [0], included: [null], }); private subscription = new Subscription(); onChange = (value: any) => {}; onTouched = () => {}; constructor(private readonly formBuilder: FormBuilder) {} ngOnInit(): void { this.form.get('performance').valueChanges.subscribe(value => { this.selectBenefit(value); }); const sub = this.form.valueChanges.subscribe(value => this.onChange(value)); this.subscription.add(sub); this.setCalculateTotalKRValue(); } ngOnDestroy(): void { this.subscription.unsubscribe(); } writeValue(value: any): void { this.form.patchValue(value || null); } registerOnChange(onChange: any) { this.onChange = onChange; } registerOnTouched(onTouched: any) { this.onTouched = onTouched; } onBenefitRemove(): void { this.benefitRemove.emit(); } private selectBenefit(benefitValue: string): void { const selectedBenefit = this.benefitList.find( ({ value }) => value === benefitValue ); this.form.patchValue({ type: selectedBenefit.extraField === 'OrdinaryBenefit' ? 'AHT' : 'UHT', performanceName: selectedBenefit.text, }); } private setCalculateTotalKRValue(): void { const nameWithStarters = [ { name: 'quantityKR', value: 0 }, { name: 'quantity', value: 0 }, { name: 'priceKR', value: 0 }, { name: 'hbtPercentage', value: 100 }, ]; const valueChangers$ = nameWithStarters.map(({ name, value }) => this.form.get(name).valueChanges.pipe(startWith(value)) ); const sub = combineLatest(valueChangers$) .pipe(map((values: ValuesTuple) => calculateTotalKr(values))) .subscribe(value => { this.form.get('totalKR').setValue(value); }); this.subscription.add(sub); } } function calculateTotalKr([ quantityKR, quantity, priceKR, hbtPercentage, ]: ValuesTuple): number { return (quantityKR * quantity - priceKR) * (hbtPercentage / 100); }
Оригинал: “https://dev.to/tomwebwalker/set-value-of-one-control-by-other-controls-in-angular-reactiveforms-18d1”