选择“所有垫子”选项并取消选择“全部”

问题描述 投票:0回答:7

我的情况如下:

我想要实现的是:

  1. 当用户单击全部时,将选择所有选项,当用户再次单击全部时,将取消选择所有选项。
  2. 如果选中All选项并且用户单击除
    All
    之外的任何其他复选框,则应取消选择All和单击的复选框。
  3. 当用户一一选择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

angular-material2 angular6 multi-select
7个回答
52
投票

使用如下代码创建功能,单击每个

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>

40
投票

您可以轻松做到这一点,无需通过添加复选框向数据源添加新选项。

参见:

演示

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>


20
投票
另一种方法是使用

@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>


6
投票
这是如何扩展材质选项组件的示例。

参见 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; }
    

0
投票
另一种可能的解决方案:

在模板中使用

<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>
    

0
投票
其他答案有一些问题。最重要的是他们正在监听不完整的点击事件(用户可以通过键盘上的空格键选择一个选项)。

我创建了一个可以解决所有问题的组件:

@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>

    

0
投票
根据@Yaseen的回答,这是反应式形式的答案:

Demo

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>

© www.soinside.com 2019 - 2024. All rights reserved.