表单包含自动完成字段。当一个元素被选中时,它应该从下拉列表中消失,并在移除芯片时重新添加。如何重构listeningControls()
以摆脱重复代码?有一个想法是将 valueChanges 挂parentFormGroup
在管道上和管道中,以过滤掉没有交互的控件。但是没有了解如何区分这些控件
Angular Material 文档中重新设计的示例
export class ChipsAutocompleteExample {
visible = true;
selectable = true;
removable = true;
fruitCtrl = new FormControl();
filteredFruits: Observable < string[] > ;
fruits: string[] = ['Lemon'];
allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];
cityCtrl = new FormControl();
filteredCityList: Observable < string[] > ;
allCity: string[] = ['LA', 'Chicago', 'London', 'Milan'];
cityList: string[] = ['Chicago'];
@Input() parentFormGroup: FormGroup;
@ViewChild('fruitInput', {
static: false
}) fruitInput: ElementRef < HTMLInputElement > ;
@ViewChild('cityInput', {
static: false
}) cityInput: ElementRef < HTMLInputElement > ;
constructor(private fb: FormBuilder) {
this.createControlForAutocomplete();
this.listeningControls();
}
listeningControls(): void {
this.filteredFruits = this.parentFormGroup.get('fruit').pipe(
startWith(null),
map((fruit: string | null) => fruit ? this._filter(fruit, 'fruit') : this.allFruits.slice()),
map(fruits => fruits.filter(fruit => !this.fruits.includes(fruit))),
);
this.filteredCityList = this.cityCtrl.valueChanges.pipe(
startWith(null),
map((city: string | null) => city ? this._filter(city, 'city') : this.allCity.slice()),
map(cityList => cityList.filter(city => !this.cityList.includes(city))),
);
}
createControlForAutocomplete(): void {
this.fruitCtrl = this.fb.control('');
this.cityCtrl = this.fb.control('');
}
remove(value: string, ctrlName: string): void {
const control = this.parentFormGroup.get(ctrlName);
const index = control.value.indexOf(value);
if (index > -1) {
const temp = [...control.value];
temp.splice(index, 1);
control.setValue([...temp]);
}
}
selected(event: MatAutocompleteSelectedEvent, ctrlName: 'fruit' | 'city'): void {
const control = this.parentFormGroup.get(ctrlName);
const temp = [...control.value, event.option.value];
control.setValue(temp);
(this[ctrlName + 'Input'] as ElementRef < HTMLInputElement > ).nativeElement.value = '';
}
}
private _filter(value: string, ctrlName: 'fruit' | 'city'): string[] {
const currentControl = this[ctrlName];
const selectedItems = this.parentFormGroup.get(ctrlName).value;
if (!value) {
return currentControl.slice();
}
currentControl.filter(item => item.toLowerCase().includes(value));
return currentControl.filter(item => {
return item !== value && !selectedItems.includes(item);
});
}
}
<mat-form-field class="example-chip-list">
<mat-chip-list #chipFruitList aria-label="Fruit selection">
<mat-chip *ngFor="let fruit of fruits" [selectable]="selectable" [removable]="removable" (removed)="remove(fruit)">
{{fruit}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input placeholder="New fruit..." #fruitInput [formControl]="fruitCtrl" [matAutocomplete]="auto" [matChipInputFor]="chipFruitList">
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event, 'fruit')">
<mat-option *ngFor="let fruit of filteredFruits | async" [value]="fruit">
{{fruit}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="example-chip-list">
<mat-chip-list #chipCityList aria-label="City selection">
<mat-chip *ngFor="let city of cityList" [selectable]="selectable" [removable]="removable" (removed)="remove(city)">
{{city}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input placeholder="New city..." #cityInput [formControl]="cityCtrl" [matAutocomplete]="autoCity" [matChipInputFor]="chipCityList">
</mat-chip-list>
<mat-autocomplete #autoCity="matAutocomplete" (optionSelected)="selected($event, 'city')">
<mat-option *ngFor="let city of filteredCityList | async" [value]="city">
{{fruit}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
没错,你需要在构造函数中进行过滤。您需要再添加一个
map
:好吧,在模板中进一步