Динамические формы Angular 4: зависимое выпадающее меню

Я создаю динамическую форму на основе Динамических форм Angular 4.

Все отлично получается! Однако у меня возникла проблема с выпадающим списком. Я хотел бы иметь зависимый выпадающий список. Когда пользователь выбирает значение в раскрывающемся списке, он отображает флажки на основе атрибута — возможно, name.

сервис

  new DropdownInput({
    key: 'dropdown',
    label: 'Dropdown Testing',
    options: [
      {key: 'example1',  value: 'Example 1'},
      {key: 'example2',  value: 'Example 2'}
    ],
    order: 1
  }),

  new CheckboxInput({
    key: 'checkbox1',
    label: 'checkbox1 - example1',
    name: 'example1',
    order: 2
  }),

  new CheckboxInput({
    key: 'checkbox2',
    label: 'checkbox2 - example1',
    name: 'example1',
    order: 3
  }),

  new CheckboxInput({
    key: 'checkbox3',
    label: 'checkbox3 - example2',
    name: 'example2',
    order: 4
  }),

  new CheckboxInput({
    key: 'checkbox4',
    label: 'checkbox4 - example2',
    name: 'example2',
    order: 5
  })

html

<!-- CHECKBOX -->

<div class="col-xs-12" *ngSwitchCase="'checkbox'">

  <input class="form-check-input"
         type="checkbox"
         [formControlName]="input.key"
         [id]="input.key"
         [name]="input.name">

  <label class="control-label"
         [attr.for]="input.key">{{input.label}}</label>
  <a class="info-tooltip"><i class="fa fa-question-circle" aria-hidden="true"></i></a>

  <span class="help-block"
        *ngIf="!isValid">{{inputError}}</span>

</div>

<!-- DROPDOWN -->

<div class="col-xs-12" *ngSwitchCase="'dropdown'">

  <label class="control-label"
         [attr.for]="input.key">{{input.label}}</label>
  <a class="info-tooltip"><i class="fa fa-question-circle" aria-hidden="true"></i></a>

  <span class="help-block"
        *ngIf="!isValid">{{inputError}}</span>

  <select [id]="input.key"
          [formControlName]="input.key">
    <option *ngFor="let opt of input.options"
            [value]="opt.key">{{opt.value}}</option>
  </select>

</div>

Итак, в этом примере, если пользователь нажмет на Пример 1, я бы хотел отображать только флажки 1 и 2. Возможно ли это? Должен ли я форматировать данные по-другому?

Примечание 1. Я нашел ссылку о том, как перейти от зависимого раскрывающегося списка к другому (Динамические формы Angular 2: как создать зависимый раскрывающийся список), но не знаете, как эффективно использовать его с флажками.

Примечание 2. Причина, по которой мой флажок отделен от текстового поля (не показано), заключается в том, как они отображаются визуально в приложении. Я знаю, что могу объединить их для получения менее/более эффективного кода.


person JessySue    schedule 16.01.2018    source источник


Ответы (1)


Я бы добавил одну опцию под названием showWhen к базовой модели:

base.model.ts

export class BaseModel<T> {
  value: T;
  key: string;
  label: string;
  required: boolean;
  order: number;
  controlType: string;
  showWhen: ControlCondition; <===================== new option

  constructor(options: {
    value?: T,
    key?: string,
    label?: string,
    required?: boolean,
    order?: number,
    controlType?: string,
    showWhen?: ControlCondition
  } = {}) {
    this.value = options.value;
    this.key = options.key || '';
    this.label = options.label || '';
    this.required = !!options.required;
    this.showWhen = options.showWhen;
    this.order = options.order === undefined ? 1 : options.order;
    this.controlType = options.controlType || '';
  }
}

export class ControlCondition {
  key: string;
  value: string;
}

Как видите, требуется key и value. В зависимости от этих значений мы можем решить, показывать управление или нет.

Теперь вы можете описать условие для отображения ваших элементов управления, например:

new DropdownInput({
  key: 'dropdown',
  label: 'Dropdown Testing',
  options: [
    { key: 'example1', value: 'Example 1' },
    { key: 'example2', value: 'Example 2' }
  ],
  order: 1
}),

new CheckboxInput({
  key: 'checkbox1',
  label: 'checkbox1 - example1',
  showWhen: {
    key: 'dropdown',   // if control with key `dropdown` has value `example 1` then show
    value: 'example1',
  },
  order: 2
}),

Теперь перейдите к компоненту, который называется DynamicFormQuestionComponent в руководстве по angular. В моем примере я назвал его DynamicFormComponent. Здесь нам нужно добавить логику для отображения/скрытия элемента управления:

динамическая форма.component.ts

export class DynamicFormComponent implements OnInit, OnDestroy {
  @Input() input: BaseModel<any>;
  @Input() form: FormGroup;

  control: FormControl;

  hidden: boolean;

  subscription: Subscription;

  ngOnInit() {
    this.control = this.form.get(this.input.key) as FormControl;
    this.setUpConditions();
  }

  setUpConditions() {
    if (!this.input.showWhen) {
      return;
    }

    let relatedControl = this.form.get(this.input.showWhen.key);
    if (!relatedControl) {
      return;
    }

    this.updateHidden();
    this.subscription = relatedControl.valueChanges.subscribe(x => this.updateHidden());
  }

  updateHidden(): void {
    let relatedControl = this.form.get(this.input.showWhen.key);
    this.hidden = relatedControl.value !== this.input.showWhen.value;

    this.hidden ? this.control.disable() : this.control.enable();
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

и последнее, что вам нужно сделать, это добавить *ngIf="!hidden" в шаблон

Ng-run Пример

person yurzui    schedule 16.01.2018
comment
Спасибо! У меня довольно странная просьба. Но когда я отправляю данные на сервер, мне нужно иметь данные от всех отправленных флажков. Например, предположим, что пользователь нажал на пример 2 в раскрывающемся списке и нажал только на флажок 3 (и не отметил, а затем снял). Данные читаются: dropdown: example2, checkbox3: true, но я бы хотел, чтобы данные читались: dropdown: example2, checkbox1: false, checkbox2: false, checkbox3: true, checkbox4: false. Это возможно? - person JessySue; 18.01.2018
comment
За это отвечает строка this.hidden ? this.control.disable() : this.control.enable();. Вы также можете прочитать getRawValue из formGroup. я обновил пример - person yurzui; 18.01.2018
comment
Вы также можете вызвать значение метода reset, если this.hidden равно true - person yurzui; 18.01.2018