angularangular-reactive-formsform-controlmat-selectmat-option

How to deselect "Select All" option in the mat-select


I am using Angular 15, and make this multiple selection mat-select drop-down with a "Select All" option:

<mat-form-field appearance="fill">
    <mat-label>Select Months</mat-label>
    <mat-select multiple matNativeControl required (selectionChange)="onMonthsSelected($event)" [formControl]="selected_months">
        <mat-option [value]="0" (click)="selectAllMonths(ev)" #ev>Select All</mat-option>   
        <mat-option *ngFor="let month of months" [value]="month">
            {{month}}
        </mat-option>
    </mat-select>
</mat-form-field>

In TS file:

months:any[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
selected_months = new FormControl();

onMonthsSelected($event: any) {
    // What to do?
}

selectAllMonths(ev:any) {
    if (ev._selected) {
      this.selected_months = this.months;
      ev._selected = true;
    }
    if (!ev._selected) {
      this._selected_months.setValue([]);
    }
}

The functionality I am seeking is when all options are selected by selecting each "month", the Select All option will be checked. If one option is deselected after all options are selected, the Select All option will be unchecked. I don't know how to implement this through the function onMonthsSelected, any ideas?


Solution

    1. You need to get the reference for the Select All option in the component via the @ViewChild decorator.

    2. The onMonthsSelected should prevent the event when the Select All option is selected/deselected.

    3. Comparing the selected months $event.value against the months array, if matching all then call the .select() API, otherwise .deselect() API for the mat options.

    import { ViewChild } from '@angular/core';
    
    @ViewChild('ev') selectAllOption!: MatOption;
    
    onMonthsSelected($event: any) {
    
      if ($event.value && $event.value[0] === 0) return;
    
      if (
        this.months.length == $event.value.length &&
        this.months.every((x, i) => x === $event.value[i])
      )
        this.selectAllOption.select(false);
      else this.selectAllOption.deselect(false);
    }
    

    Demo @ StackBlitz