Angular 中的互斥选项
Mutually exclusive options in Angular
让我试着解释一下我的情况...
我有一个 <form>
,其中包含一个 FormArray
。每个FormArray
组都有“食物”control
,每个组都是<select>
。
所有 select 都由 单个 array
.
填充
我想要实现的是:
每个 select 的选项必须完全 selected...换句话说,
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>
;
中 select 编辑的选项
2 - 创建一个自定义验证器并告诉用户他不能在 2 或更多 select 秒内 select 一个选项。
3 - 从其他 selects.
中完全删除 selected 选项
我更喜欢第一个。选项,但是我找不到执行此操作的方法。有人可以告诉我一些事情开始吗?我希望问题足够清楚。
这是一个demo。
这可以通过订阅控件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);
}
构建我自己的解决方案:
我创建了一个方法来检查它是否应该被禁用:
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"
...
这不是最优解吗?也许...如果您有其他选择,请告诉我。
让我试着解释一下我的情况...
我有一个 <form>
,其中包含一个 FormArray
。每个FormArray
组都有“食物”control
,每个组都是<select>
。
所有 select 都由 单个 array
.
我想要实现的是:
每个 select 的选项必须完全 selected...换句话说,
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 或更多 select 秒内 select 一个选项。
3 - 从其他 selects.
中完全删除 selected 选项我更喜欢第一个。选项,但是我找不到执行此操作的方法。有人可以告诉我一些事情开始吗?我希望问题足够清楚。
这是一个demo。
这可以通过订阅控件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);
}
构建我自己的解决方案:
我创建了一个方法来检查它是否应该被禁用:
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"
...
这不是最优解吗?也许...如果您有其他选择,请告诉我。