选择所有垫选项,然后取消选择全部

时间:2018-07-29 11:55:56

标签: angular-material2 angular6 multi-select

我的情况如下:

enter image description here

我要实现的是:

  1. 当用户单击全部时,应选择所有选项;当用户再次单击全部时,应删除所有选项。
  2. 如果选中了全部选项,并且用户单击了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

6 个答案:

答案 0 :(得分:9)

在每个mat-optionselect()/deselect()的所有选项上单击,使用下面的代码创建函数:

请参阅stackblitz:https://stackblitz.com/edit/angular-material-with-angular-v5-jsgvx6?file=app/app.component.html

TS:

tosslePerOne(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)="tosslePerOne(allSelected.viewValue)">
            {{filters.value}}
        </mat-option>
        <mat-option #allSelected (click)="toggleAllSelection()" [value]="0">All</mat-option>
    </mat-select>
</form>

答案 1 :(得分:8)

您只需无需即可执行此操作,而无需通过添加复选框将新选项添加​​到数据源。

请参阅:Demo

touchesEnded
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;
} 

答案 2 :(得分:2)

这里是如何扩展材料选项组件的示例。

请参阅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;
}

答案 3 :(得分:0)

执行此操作的另一种方法是使用 @ViewChild 选择器来获取垫选择组件,并触发选中或未选中的垫选项项。我们还需要一个变量来保存选定的实际状态,以在每次单击时选择或取消选择所有元素。希望会有所帮助。

  import {MatOption, MatSelect} from "@angular/material";
  
  export class ExampleAllSelector {
  
    myFormControl = new FormControl();
    elements: any[] = [];

    allSelected = false;

    @ViewChild('mySel') mySel: MatSelect;

    constructor() {}

    toggleAllSelection() {
      this.allSelected = !this.allSelected;  // to control select-unselect
      
      if (this.skillAllSelected) {
        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>

答案 4 :(得分: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>

答案 5 :(得分:0)

其他答案有一些问题。最重要的是,他们正在监听尚未完成的click事件(用户可以通过键盘上的空格键选择一个选项)。

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

unique()
@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),
    );
  }
}