Обработка формы отключения / включения при изменении значения - PullRequest
0 голосов
/ 04 августа 2020

У меня есть группа форм, в которой различные элементы управления формой связаны друг с другом. Каждый элемент управления формой доступен только в том случае, если предыдущий был заполнен. Кроме того, если элемент управления формой очищен, все следующие элементы управления формой должны быть очищены и отключены.

Я сделал небольшой пример, чтобы объяснить вариант использования. В моем примере я обрабатываю четыре элемента управления формой, тогда как в моем реальном варианте использования у меня больше элементов управления формой. Я не думаю, что эта реализация элегантна и плохо масштабируется. У вас есть лучшая реализация?

Рабочий пример в stackblitz

export class AppComponent implements OnInit {
  public myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  public ngOnInit(): void {
    this.myForm = this.getMyForm();
    this.handleFormValueChanges(this.myForm);
  }

  private getMyForm(): FormGroup {
    return this.fb.group({
      company: null,
      country: [{
        value: null,
        disabled: true
      }],
      user: [{
        value: null,
        disabled: true
      }],
      adress: [{
        value: null,
        disabled: true
      }]
    });
  }

  /**
   * Handle myForm value changes (didn't handle unsubscriptions because it is just an example)
   * TODO: Find another implementation
   */
  private handleFormValueChanges(form: FormGroup): void {
    form.get("company").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("country").reset();
        form.get("country").disable();

        form.get("user").reset();
        form.get("user").disable();

        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("country").enable();
      }
    });

    form.get("country").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("user").reset();
        form.get("user").disable();

        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("user").enable();
      }
    });

    form.get("user").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("adress").enable();
      }
    });
  }
}

РЕДАКТИРОВАТЬ: В итоге я реализовал небольшую вариацию решения Фабио Карпинато

Вот stackblitz

import { Component, OnInit, ChangeDetectionStrategy } from "@angular/core";
import { FormGroup, FormBuilder } from "@angular/forms";
import { merge } from "rxjs";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnInit {
  public myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  public ngOnInit(): void {
    this.myForm = this.getMyForm();
    this.handleFormValueChanges(this.myForm);
  }

  private getMyForm(): FormGroup {
    return this.fb.group({
      company: null,
      country: [{ value: null, disabled: true }],
      user: [{ value: null, disabled: true }],
      adress: [{ value: null, disabled: true }]
      /*
      ... other formcontrols
      */
    });
  }

  /**
   * Handle myForm value changes (didn't handle unsubscriptions nor debounceTime because it is just an example)
   */
  private handleFormValueChanges(form: FormGroup): void {
    const controlDisabledDependencies: { [controlKey: string]: string } = {
      company: null,
      country: "company",
      user: "country",
      adress: "user"
    };

    merge(
      ...Object.keys(controlDisabledDependencies).map(
        (controlKey: string) => form.get(controlKey).valueChanges
      )
    ).subscribe(() => {
      Object.keys(controlDisabledDependencies).forEach((controlKey: string) => {
        if (
          form.get(controlDisabledDependencies[controlKey]) &&
          !form.get(controlDisabledDependencies[controlKey]).value
        ) {
          form.get(controlKey).disable({ emitEvent: false, onlySelf: true });
          form
            .get(controlKey)
            .reset(null, { emitEvent: false, onlySelf: true });
        } else {
          form.get(controlKey).enable({ emitEvent: false, onlySelf: true });
        }
      });
    });
  }
}

Ответы [ 2 ]

1 голос
/ 04 августа 2020

Вы можете упростить это, создав карту зависимостей.

Например, адрес зависит от страны. чтобы вы могли добавить на свою карту что-то вроде:

map = ['address' => 'country']

, где используемые вами ключи являются ключами элементов управления формы.

, тогда вы можете подписаться на изменения значений формы, и каждый раз, когда вы вводите подписку, вы будете oop через все ключи управления формой и начнете проверять значения, а затем решите, что отключить на основе карта зависимостей.

Это становится легко масштабируемым, потому что вы можете добавлять зависимости в элементы управления формы, не меняя logi c, вам просто нужно будет добавить запись на карту.

I написал для вас простой пример https://stackblitz.com/edit/angular-ivy-qxfkdz.

0 голосов
/ 04 августа 2020

Ваш подход по-прежнему может быть лучшим для описанного вами сценария из-за последовательного характера вашей формы.

Однако альтернативным подходом будет вызов .valueChanges() непосредственно в самой форме, а не отдельные элементы управления формой. Это даст вам родительский объект формы, который будет генерироваться при изменении любого из вложенных элементов управления формой. Затем вы можете объединить ваши logi c в один вызов подписки, например

form.valueChanges.subscribe((value: any) => {
  if (!value.company) {
    form.get("country").reset({ emitEvent: false });
    form.get("country").disable({ emitEvent: false });
  } else {
    form.get("country").enable({ emitEvent: false });
  }

  if (!value.country) {
    form.get("user").reset({ emitEvent: false });
    form.get("user").disable({ emitEvent: false });
  } else {
    form.get("user").enable({ emitEvent: false });
  }

  ...
});

Примечание: {emitEvent: false} не позволит вашей форме инициировать обнаружение изменений на самой себе. Это важно, поскольку, если этого не сделать, вы застрянете в бесконечном l oop обновлениях.

Поскольку ваш дизайн образует своего рода цепочку FormControls, и каждый оператор if будет фактически повторяется на каждом элементе цепочки, у меня может возникнуть соблазн вместо getMyForm() вернуть FormArray вместо FormGroup. Это позволит вам перебирать ваши FormControls, как если бы они были сохранены в массиве, и применять одну и ту же функцию к каждому, что будет масштабироваться намного эффективнее. Это немного сложнее (но все же возможно) с FormGroup.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...