选择所有垫子选项并取消选择全部
Posted
技术标签:
【中文标题】选择所有垫子选项并取消选择全部【英文标题】:Select All mat option and deselect All 【发布时间】:2019-01-05 21:14:52 【问题描述】:我的场景如下:
我要实现的是:
-
当用户点击All时,所有选项都会被选中,当用户再次点击All时,所有选项都会被取消。
如果 All 选项被选中并且用户单击除
All
之外的任何其他复选框,则应取消选择 All 和单击的复选框。
当用户一一选择 4 个选项时,应选择全部。
html 文件
<mat-select placeholder="User Type" formControlName="UserType" multiple>
<mat-option *ngFor="let filters of userTypeFilters" [value]="filters.key">
filters.value
</mat-option>
<mat-option #allSelected (click)="toggleAllSelection()" [value]="0">All</mat-option>
</mat-select>
TS 文件
this.searchUserForm = this.fb.group(
userType: new FormControl('')
);
userTypeFilters = [
key: 1, value: 'Value 1',
,
key: 2, value: 'Value 2',
,
key: 3, value: 'Value 3',
,
key: 4, value: 'Value 4',
]
toggleAllSelection()
if (this.allSelected.selected)
this.searchUserForm.controls.userType
.patchValue([...this.userTypeFilters.map(item => item.key), 0]);
else
this.searchUserForm.controls.userType.patchValue([]);
现在,如何实现第二点和第三点
Stackblitz 是:https://stackblitz.com/edit/angular-material-with-angular-v5-znfehg?file=app/app.component.html
【问题讨论】:
我看到第二个 senario 作品对吗? no.. 只有第一个有效.. 第二个选项是,如果选择了 All,然后用户取消选择任何选项,则应取消该选项和 All 选项 【参考方案1】:使用如下代码在点击每个mat-option
和select()/deselect()
所有选项时创建函数:
见 stackblitz:https://stackblitz.com/edit/angular-material-with-angular-v5-jsgvx6?file=app/app.component.html
TS:
togglePerOne(all)
if (this.allSelected.selected)
this.allSelected.deselect();
return false;
if(this.searchUserForm.controls.userType.value.length==this.userTypeFilters.length)
this.allSelected.select();
toggleAllSelection()
if (this.allSelected.selected)
this.searchUserForm.controls.userType
.patchValue([...this.userTypeFilters.map(item => item.key), 0]);
else
this.searchUserForm.controls.userType.patchValue([]);
HTML:
<form [formGroup]="searchUserForm" fxFlex fxLayout="column" autocomplete="off" style="margin: 30px">
<mat-select placeholder="User Type" formControlName="userType" multiple>
<mat-option *ngFor="let filters of userTypeFilters" [value]="filters.key" (click)="togglePerOne(allSelected.viewValue)">
filters.value
</mat-option>
<mat-option #allSelected (click)="toggleAllSelection()" [value]="0">All</mat-option>
</mat-select>
</form>
【讨论】:
如果我想避免在所选项目列表中看到“全部”,我该怎么办? 对不起,我可能没有解释清楚,我想避免它出现在所选项目列表中,但我不想删除相应的复选框【参考方案2】:另一种方法是使用 @ViewChild 选择器来获取 mat-select 组件并调整 mat-options 项的选中或未选中。我们还需要一个变量来保存选择的实际状态,以便在每次点击时选择或取消选择所有元素。希望会有所帮助。
import MatOption, MatSelect from "@angular/material";
export class ExampleAllSelector
myFormControl = new FormControl();
elements: any[] = [];
allSelected = false;
@ViewChild('mySel') skillSel: MatSelect;
constructor()
toggleAllSelection()
this.allSelected = !this.allSelected; // to control select-unselect
if (this.allSelected)
this.skillSel.options.forEach( (item : MatOption) => item.select());
else
this.skillSel.options.forEach( (item : MatOption) => item.deselect());
this.skillSel.close();
<mat-select #mySel placeholder="Example" [formControl]="myFormControl" multiple>
<mat-option [value]="0" (click)="toggleAllSelection()">All items</mat-option>
<mat-option *ngFor="let element of elements" [value]="element">skill.name</mat-option>
</mat-select>
【讨论】:
skillAllSelected 应该是什么? @Takatalvi 应该是“allSelected” 谢谢,在选择循环的情况下,这对我有用,我没有使用 viewChild,而是使用了 @ViewChildren('mySel') SkillSel: QueryList这是一个如何扩展材质选项组件的示例。
见 stackblitz Demo
组件:
import ChangeDetectorRef, Component, ElementRef, HostListener, HostBinding, Inject, Input, OnDestroy, OnInit, Optional from '@angular/core';
import MAT_OPTION_PARENT_COMPONENT, MatOptgroup, MatOption, MatOptionParentComponent from '@angular/material/core';
import AbstractControl from '@angular/forms';
import MatPseudoCheckboxState from '@angular/material/core/selection/pseudo-checkbox/pseudo-checkbox';
import Subject from 'rxjs';
import takeUntil from 'rxjs/operators';
@Component(
selector: 'app-select-all-option',
templateUrl: './select-all-option.component.html',
styleUrls: ['./select-all-option.component.css']
)
export class SelectAllOptionComponent extends MatOption implements OnInit, OnDestroy
protected unsubscribe: Subject<any>;
@Input() control: AbstractControl;
@Input() title: string;
@Input() values: any[] = [];
@HostBinding('class') cssClass = 'mat-option';
@HostListener('click') toggleSelection(): void
this. _selectViaInteraction();
this.control.setValue(this.selected ? this.values : []);
constructor(elementRef: ElementRef<HTMLElement>,
changeDetectorRef: ChangeDetectorRef,
@Optional() @Inject(MAT_OPTION_PARENT_COMPONENT) parent: MatOptionParentComponent,
@Optional() group: MatOptgroup)
super(elementRef, changeDetectorRef, parent, group);
this.title = 'Select All';
ngOnInit(): void
this.unsubscribe = new Subject<any>();
this.refresh();
this.control.valueChanges
.pipe(takeUntil(this.unsubscribe))
.subscribe(() =>
this.refresh();
);
ngOnDestroy(): void
super.ngOnDestroy();
this.unsubscribe.next();
this.unsubscribe.complete();
get selectedItemsCount(): number
return this.control && Array.isArray(this.control.value) ? this.control.value.filter(el => el !== null).length : 0;
get selectedAll(): boolean
return this.selectedItemsCount === this.values.length;
get selectedPartially(): boolean
const selectedItemsCount = this.selectedItemsCount;
return selectedItemsCount > 0 && selectedItemsCount < this.values.length;
get checkboxState(): MatPseudoCheckboxState
let state: MatPseudoCheckboxState = 'unchecked';
if (this.selectedAll)
state = 'checked';
else if (this.selectedPartially)
state = 'indeterminate';
return state;
refresh(): void
if (this.selectedItemsCount > 0)
this.select();
else
this.deselect();
HTML:
<mat-pseudo-checkbox class="mat-option-pseudo-checkbox"
[state]="checkboxState"
[disabled]="disabled"
[ngClass]="selected ? 'bg-accent': ''">
</mat-pseudo-checkbox>
<span class="mat-option-text">
title
</span>
<div class="mat-option-ripple" mat-ripple
[matRippleTrigger]="_getHostElement()"
[matRippleDisabled]="disabled || disableRipple">
</div>
CSS:
.bg-accent
background-color: #2196f3 !important;
【讨论】:
我喜欢这个解决方案:有没有办法让这个键盘变得友好?看起来自定义选项被 MatSelect 组件完全忽略了.. 在 Angular 10 上,我不得不删除调用 _selectViaInteraction 因为全选选项没有改变状态。【参考方案4】:只需添加一个复选框,无需即可为您的数据源添加新选项。
请参阅:Demo
import Component, VERSION, ViewChild from '@angular/core';
import FormControl from '@angular/forms';
import MatSelect from '@angular/material/select';
import MatOption from '@angular/material/core';
@Component(
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
)
export class AppComponent
@ViewChild('select') select: MatSelect;
allSelected=false;
foods: any[] = [
value: 'steak-0', viewValue: 'Steak',
value: 'pizza-1', viewValue: 'Pizza',
value: 'tacos-2', viewValue: 'Tacos'
];
toggleAllSelection()
if (this.allSelected)
this.select.options.forEach((item: MatOption) => item.select());
else
this.select.options.forEach((item: MatOption) => item.deselect());
optionClick()
let newStatus = true;
this.select.options.forEach((item: MatOption) =>
if (!item.selected)
newStatus = false;
);
this.allSelected = newStatus;
.select-all
margin: 5px 17px;
<mat-form-field>
<mat-label>Favorite food</mat-label>
<mat-select #select multiple>
<div class="select-all">
<mat-checkbox [(ngModel)]="allSelected"
[ngModelOptions]="standalone: true"
(change)="toggleAllSelection()">Select All</mat-checkbox>
</div>
<mat-option (click)="optionClick()" *ngFor="let food of foods" [value]="food.value">
food.viewValue
</mat-option>
</mat-select>
</mat-form-field>
【讨论】:
这应该是公认的答案,因为它不会在值中添加不必要的额外项目。 我分叉了你的演示。相反,我使用一个按钮完成了一个复选框。将其封装在自定义组件中,查看:stackblitz.com/edit/angular-material-select-all-button【参考方案5】:另一种可能的解决方案:
在模板中使用<mat-select [(value)]="selectedValues"
,并在组件中通过切换功能设置selectedValues
。
工作Stackblitz 演示。
组件
export class AppComponent
selectedValues: any;
allSelected = false;
public displayDashboardValues = [
key:'0', valuePositionType: 'undefined', viewValue:'Select all',
key:'1', valuePositionType: 'profit-loss-area', viewValue:'result',
key:'2', valuePositionType: 'cash-area', viewValue:'cash',
key:'3', valuePositionType: 'balance-area', viewValue:'balance',
key:'4', valuePositionType: 'staff-area' ,viewValue:'staff',
key:'5', valuePositionType: 'divisions-area', viewValue:'divisions',
key:'6', valuePositionType: 'commisions-area', viewValue:'commisions',
];
toggleAllSelection()
this.allSelected = !this.allSelected;
this.selectedValues = this.allSelected ? this.displayDashboardValues : [];
模板
<mat-select [(value)]="selectedValues" (selectionChange)="selectionChange($event)" formControlName="dashboardValue" multiple>
<mat-option [value]="displayDashboardValues[0]" (click)="toggleAllSelection()"> displayDashboardValues[0].viewValue </mat-option>
<mat-divider></mat-divider>
<div *ngFor="let dashboardPosition of displayDashboardValues">
<mat-option class="dashboard-select-option" *ngIf="dashboardPosition.key>0" [value]="dashboardPosition">
dashboardPosition.viewValue
</mat-option>
</div>
</mat-select>
【讨论】:
当您使用箭头键/单击全选时的“输入”键时会变得很奇怪【参考方案6】:其他答案存在一些问题。最重要的是他们正在监听未完成的点击事件(用户可以通过键盘上的空格键选择一个选项)。
我创建了一个可以解决所有问题的组件:
@Component(
selector: 'app-multi-select',
templateUrl: './multi-select.component.html',
styleUrls: ['./multi-select.component.scss'],
)
export class MultiSelectComponent<V> implements OnInit
readonly _ALL_SELECTED = '__ALL_SELECTED__' as const;
@Input() options: ReadonlyArray< value: V; name: string > = [];
@Input('selectControl') _selectControl!: FormControl | AbstractControl | null | undefined;
get selectControl(): FormControl
return this._selectControl as FormControl;
@Input() label: string = '';
@Input() hasSelectAllOption = false;
selectedValues: (V | '__ALL_SELECTED__')[] = [];
constructor()
ngOnInit(): void
onSelectAllOptions( isUserInput, source: selected : MatOptionSelectionChange)
if (!isUserInput) return;
this.setValues(selected ? this.options.map(o => o.value) : []);
private setValues(values: (V | '__ALL_SELECTED__')[])
const hasAllOptions = ArrayUtils.arraysAreSame(
values,
this.options.map(o => o.value),
);
if (!values.includes(this._ALL_SELECTED))
if (hasAllOptions)
values = [...values, this._ALL_SELECTED];
else if (!hasAllOptions)
values = values.filter(o => o !== this._ALL_SELECTED);
setTimeout(() =>
this.selectedValues = values;
);
this.selectControl.setValue(values.filter(o => (o as any) !== this._ALL_SELECTED));
onSelectOtherOptions( isUserInput, source: selected, value : MatOptionSelectionChange)
if (!isUserInput) return;
this.setValues(
selected ? [...this.selectedValues, value] : this.selectedValues.filter(o => o !== value),
);
<mat-form-field>
<mat-label>Choose some options</mat-label>
<mat-select multiple [value]="selectedValues">
<mat-option
*ngFor="let d of options"
[value]="d.value"
(onSelectionChange)="onSelectOtherOptions($event)"
>
d.name
</mat-option>
<mat-option
*ngIf="hasSelectAllOption"
[value]="_ALL_SELECTED"
(onSelectionChange)="onSelectAllOptions($event)"
>
Select all
</mat-option>
</mat-select>
</mat-form-field>
【讨论】:
能否分享完整的 stackblitz 示例?谢谢以上是关于选择所有垫子选项并取消选择全部的主要内容,如果未能解决你的问题,请参考以下文章
复制所有文本后隐藏复制和取消选择 UITextView 选项