How to limit Angular Material multiple select items to N items?

You can do this using the disabled property on the mat-option like so:

<mat-select formControlName="myCtrl" multiple>
            <mat-option [disabled]="formGroup.get('myCtrl').value?.length > 2 && !formGroup.get('myCtrl').value?.includes(o)"
                        *ngFor="let o of itemList"
                        [value]="o">{{o.name}}
            </mat-option>
</mat-select>

The best solution is based on only if you disable only unselected options. Otherwise it is meaningless because after you disable all options, then how is that possible to unselect any of options?

in HTML component:

<mat-form-field>
  <mat-select placeholder="Category" [formControl]="categories" multiple>
    <mat-option *ngFor="let cat of categoryArr" [value]="cat.id"
      [disabled]="isOptionDisabled(cat.id)">
      {{cat.title}}
    </mat-option>
  </mat-select>
</mat-form-field>

in controller:

isOptionDisabled(opt: any): boolean {
  return this.categories.value.length >= 3 && !this.categories.value.find(el => el == opt)
}

Now: Only already selected options are enable to do something, other options are disabled, as follows:

Only already selected options are enable to do something, other options are disabled

User can uncheck any of checked options so that user have chance to be able to do check/uncheck on the form field.


Set the selectionChange output event on the mat-select component, point it to your component function: (selectionChange)="changed()".

snippet:

<mat-select placeholder="Toppings" [formControl]="toppings" (selectionChange)="changed()" multiple>

In your component create a global variable named mySelections. This will store your selections :) It will hold an array of strings.

It looks like this:

mySelections: string[];

changed() {
  if (this.toppings.value.length < 3) {
    this.mySelections = this.toppings.value;
  } else {
    this.toppings.setValue(this.mySelections);
  }
}

Change the number 3 to N and presto, you're done.