Рубрики
Без рубрики

Установите значение одного контроля другими элементами управления в угловых реактивных формах

Создавая форму с контролем, значение относится к другим значениям управления, я заметил, что это Q … Помечено угловой, RXJS, Tymdercript, JavaScript.

Создавая форму с контролем, значение относится к другим значениям управления, я заметил, что это довольно легко использовать комбинация Оператор от 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”