Взаимоисключающие опции в Angular

Попробую немного объяснить мою ситуацию...

У меня есть <form>, который содержит FormArray. В каждой FormArray группе есть еда control, и каждая из них <select>.

Все выборки заполняются одним array.

Чего я пытаюсь достичь, так это:

Параметры каждого выбора должны быть выбраны исключительно... другими словами, результат в FormArray должен содержать только уникальные элементы.


Мой фактический код:

HTML:

<form [formGroup]="formGroup">
  <div>
    <button mat-raised-button color="primary" type="button" (click)="addItem()">
      <mat-icon>add</mat-icon>Add food
    </button>
  </div>
  <ng-container
    formArrayName="items"
    *ngFor="let item of formArray.controls; index as i"
  >
    <mat-card>
      <mat-card-title>
        <h3>Item nº {{ i + 1 }}</h3>
        <button
          mat-mini-fab
          color="warn"
          matTooltip="Remove"
          type="button"
          (click)="removeItem(i)"
        >
          <mat-icon>delete</mat-icon>
        </button>
      </mat-card-title>

      <mat-card-content [formGroupName]="i">
        <mat-select
          formControlName="food"
          name="food"
          placeholder="Favorite food"
        >
          <mat-option
            [value]="food.value"
            *ngFor="let food of foods"
          >
            {{ food.viewValue }}
          </mat-option>
        </mat-select>
      </mat-card-content>
    </mat-card>
  </ng-container>
</form>

Компонент:

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
  readonly foods: readonly Food[] = [
    { value: 'steak-0', viewValue: 'Steak' },
    { value: 'pizza-1', viewValue: 'Pizza' },
    { value: 'tacos-2', viewValue: 'Tacos' }
  ];
  readonly formArray = this.formBuilder.array([]);
  readonly formGroup = this.formBuilder.group({
    items: this.formArray
  });
  
  constructor(private readonly formBuilder: FormBuilder) {}
  
  addItem(): void {
    this.formArray.push(
      this.formBuilder.group({
        food: ''
      })
    )
  }
  
  removeItem(index: number): void {
    this.formArray.removeAt(index);
  }
}

Я хочу знать, что является лучшим вариантом для достижения этой цели.

Пока думаю в 3-х вариантах:

1 - Отключить опции, которые уже были выбраны в другом <select>;

2 - Создайте собственный валидатор и сообщите пользователю, что он не может выбрать вариант из 2 или более вариантов.

3 – Полностью удалить выбранные параметры из других вариантов выбора.

Я предпочитаю 1-й. вариант, однако я не могу найти способ сделать это. Может кто-нибудь показать мне что-нибудь для начала? Я надеюсь, что вопрос достаточно ясен.

Вот демонстрация.


person dev_054    schedule 27.08.2017    source источник
comment
Я нашел это (довольно старое), написанное в jQuery: rndnext.blogspot.com.br/2009/08/.   -  person dev_054    schedule 27.08.2017


Ответы (2)


Просто создайте собственное решение:

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

isOptionDisabled(value: string, index: number): boolean {
  const foodsFormArray = this.formArray.value as readonly FoodFormGroup[];
  const foundIndex = foodsFormArray.findIndex(({ food }) => food === value);

  return foundIndex !== -1 && foundIndex !== index;
}

Итак, в шаблоне...

...
<mat-option
  [disabled]="isOptionDisabled(food.value, i)"
  [value]="food.value"
  *ngFor="let food of foods"
...

ДЕМО

Разве это не оптимальное решение? Может быть... если у вас есть другой вариант сделать это, дайте мне знать.

person dev_054    schedule 27.08.2017

Этого можно добиться, подписавшись на valueChanges контроля,

this.formGroup.controls['items'].valueChanges.subscribe(
   d=>{
       _.remove(this.foods,(item)=>{return item=== d[0].food})
 })

Внутри подписки удалите элемент из массива.

При удалении снова нажмите объект в массив, как показано ниже,

removeItem(index: number) {
      this.foods.push(this.formArray.controls[index].controls["food"].value);
      this.formArray.removeAt(index);
}

ОБНОВЛЕН ПЛАНКЕР ДЛЯ ЖИВОЙ ДЕМО

person Aravind    schedule 27.08.2017
comment
Спасибо за ваш ответ, но он не работает. Всякий раз, когда вы выбираете параметр, он удаляется из текущего выбора, поэтому у вас есть пустой выбор. Просто посмотри на свой плункер.. - person dev_054; 27.08.2017
comment
@ dev_054 Можете ли вы четко объяснить пробел в моем коде. - person Aravind; 27.08.2017