我的情况如下:
我想要实现的是:
All
之外的任何其他复选框,则应取消选择All和单击的复选框。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
使用如下代码创建功能,单击每个
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>
您可以轻松做到这一点,无需通过添加复选框向数据源添加新选项。
参见: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>
@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>
参见 stackblitz
组件:
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;
}
在模板中使用
<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>
我创建了一个可以解决所有问题的组件:
@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>
import { Component, VERSION, ViewChild } from '@angular/core';
import { FormControl, FormGroup, FormBuilder } 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;
form: FormGroup;
foods: any[] = [
{ value: 'steak-0', viewValue: 'Steak' },
{ value: 'pizza-1', viewValue: 'Pizza' },
{ value: 'tacos-2', viewValue: 'Tacos' },
];
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
food: [[]],
});
}
toggleAllSelection() {
const allSelected =
this.form.get('food').value.length === this.foods.length;
this.form
.get('food')
.setValue(allSelected ? [] : this.foods.map((food) => food.value));
this.allSelected = !allSelected;
}
optionClick() {
const selectedValues = this.form.get('food').value;
this.allSelected = selectedValues.length === this.foods.length;
}
}
.select-all{
margin: 5px 17px;
}
<mat-form-field [formGroup]="form">
<mat-label>Favorite food</mat-label>
<mat-select #select multiple formControlName="food">
<div class="select-all">
<mat-checkbox (change)="toggleAllSelection()" [checked]="allSelected"
>Select All</mat-checkbox
>
</div>
<mat-option
*ngFor="let food of foods"
[value]="food.value"
(click)="optionClick()"
>
{{ food.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>