Multi-select Dropdown in Angular Material using ngx-mat-select-search

Multiselect dropdowns allow users to choose more than one value at a time. In this tutorial, you will learn how to add a multi-select drop-down selection in Angular using the Material library. Multiselect dropdown with checkboxes and select all that can be easily created using this awesome library.

While using the material library in the Angular project, you may have missed the Select box which allows multiple value selections. Using the Material drop-down you can only select a single value.

In this guide, we will discuss how to enable multiple selections of value in material styles drop-down control using the ngx-mat-select-search library package.

The NGX Mat Select Search library, not only allows the user to select more than one value but also provides a number of other useful features like:

  • Clear selection control
  • Options grouping
  • Server-side results
  • Select/ Unselecte All option
  • Infinite Scroll with huge options

 

How to Add Material Multi-Select Drop-Down in Angular app?

Follow these quick steps to create a multi-select drop down with checkboxes and filter search using Material library:

Step 1 – Create Angular App

Step 2 – Install Material and ngx-mat-select-search Libraries

Step 3 – Update App Module with Required Modules

Step 4 – Add HTML Template

Step 5 – Update Component TS Class

Step 6 – See In Action

 

Step 1 – Create an Angular App

Before creating a new Angular app, make sure you have installed the latest version on Angular CLI tool:

npm install -g @angular/cli

 

Create a new Angular project of the name provided by executing the below command:

ng new angular-multi-select-app

 

Move into the application directory:

cd angular-multi-select-app

 

Step 2 – Install Material and ngx-mat-select-search Libraries

next, we will be installing the Material UI library and NGX Mat select search library by executing below npm commands:

Install Material Library

ng add @angular/material

? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink
? Set up global Angular Material typography styles? No   
? Include the Angular animations module? Include and enable animations

 

Install NGX Mat Select Search library

npm install ngx-mat-select-search

 

Step 3 – Update App Module with Required Modules

After installing the required npm libraries, we need to import the modules in the App Module of the application. This will enable us to use various API components on our pages.

We will import the following modules to set up multiple selection dropdowns:

Forms module including FormsModule and ReactiveFormsModule (If using reactive forms approach)

Material modules including MatSelectModule and MatFormFieldModule

Last but not least the NgxMatSelectSearchModule which will help to create multiple selections with filter and checkbox selection support.

Open the app.module.ts file and update it as shown below:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

// NGX Multi Select
import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';

// Material modules
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    FormsModule,
    BrowserAnimationsModule,
    MatSelectModule,
    MatFormFieldModule,
    NgxMatSelectSearchModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

 

Step 4 – Add HTML Template

The NGX Mat select with multiple selection can be easily created by the fusion on <mat-select> provided by Material and <ngx-mat-select-search> provide by NGX library components.

Open the app.component.html file and update it with following template html:

<div class="wrapper">
  <div class="inner-wrap">
    <h3>Material Multi Select Dropdown with search and checkboxes</h3>
    <mat-form-field>
      <mat-select
        [formControl]="carCtrl"
        placeholder="Car"
        [multiple]="true"
        #singleSelect
      >
        <mat-option>
          <ngx-mat-select-search
            [formControl]="carFilterCtrl"
            placeholderLabel="Find cars..."
            noEntriesFoundLabel="'no matching found'"
            [showToggleAllCheckbox]="true"
            toggleAllCheckboxTooltipMessage="Select / Unselect All"
            [toggleAllCheckboxIndeterminate]="isIndeterminate"
            [toggleAllCheckboxChecked]="isChecked"
            (toggleAll)="toggleSelectAll($event)"
          >
            <mat-icon ngxMatSelectSearchClear>delete</mat-icon>
          </ngx-mat-select-search>
        </mat-option>

        <mat-option *ngFor="let car of filteredCars | async" [value]="car">
          {{ car.name }}
        </mat-option>
      </mat-select>
    </mat-form-field>
  </div>
  <div class="inner-wrap">
    <h3>Selected Values</h3>
    <ul *ngFor="let car of carCtrl?.value">
      <li>{{ car.name }}</li>
    </ul>
  </div>
</div>

On the ngx-mat-select-search, we already added the properties to configure select box with filter search, checkboxes, tooltip and custom labels. You can check more API properties here.

 

Step 5 – Update Component TS Class

Next. open the app.component.ts file to add filter methods, and select toggle and initiation data objects. Update the file with the following code:

import { Component, ViewChild } from '@angular/core';
import { ReplaySubject, Subject, take, takeUntil } from 'rxjs';
import { UntypedFormControl } from '@angular/forms';
import { MatSelect } from '@angular/material/select';

export interface Car {
  id: string;
  name: string;
}

/** list of cars */
export const CARS: Car[] = [
  { name: 'Mercedes-Benz', id: 'A' },
  { name: 'Tesla', id: 'B' },
  { name: 'BMW', id: 'C' },
  { name: '	Volvo', id: 'D' },
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  /** list of cars */
  protected cars: Car[] = CARS;

  /** control for the selected car */
  public carCtrl: UntypedFormControl = new UntypedFormControl();

  /** control for the MatSelect filter keyword */
  public carFilterCtrl: UntypedFormControl = new UntypedFormControl();

  /** list of cars filtered by search keyword */
  public filteredCars: ReplaySubject<Car[]> = new ReplaySubject<Car[]>(1);

  @ViewChild('singleSelect', { static: true })
  singleSelect!: MatSelect;

  /** Subject that emits when the component has been destroyed. */
  protected _onDestroy = new Subject<void>();

  /** flags to set the toggle all checkbox state */
  isIndeterminate = false;
  isChecked = false;

  constructor() {}

  ngOnInit() {
    // set initial selection
    this.carCtrl.setValue([this.cars[1], this.cars[2]]);

    // load the initial car list
    this.filteredCars.next(this.cars.slice());

    // listen for search field value changes
    this.carFilterCtrl.valueChanges
      .pipe(takeUntil(this._onDestroy))
      .subscribe(() => {
        this.filterCars();
      });
  }

  ngAfterViewInit() {
    this.setInitialValue();
  }

  ngOnDestroy() {
    this._onDestroy.next();
    this._onDestroy.complete();
  }

  /**
   * Sets the initial value after the filteredCars are loaded initially
   */
  protected setInitialValue() {
    this.filteredCars
      .pipe(take(1), takeUntil(this._onDestroy))
      .subscribe(() => {
        this.singleSelect.compareWith = (a: Car, b: Car) =>
          a && b && a.id === b.id;
      });
  }

  protected filterCars() {
    if (!this.cars) {
      return;
    }
    // get the search keyword
    let search = this.carFilterCtrl.value;
    if (!search) {
      this.filteredCars.next(this.cars.slice());
      return;
    } else {
      search = search.toLowerCase();
    }
    // filter the cars
    this.filteredCars.next(
      this.cars.filter((car) => car.name.toLowerCase().indexOf(search) > -1)
    );
  }

  toggleSelectAll(selectAllValue: boolean) {
    this.filteredCars
      .pipe(take(1), takeUntil(this._onDestroy))
      .subscribe((val) => {
        if (selectAllValue) {
          this.carCtrl.patchValue(val);
        } else {
          this.carCtrl.patchValue([]);
        }
      });
  }
}

 

Step 6 – See In Action

We are done with implementation stuff. Now you can run your application by hitting the following command:

npm start

It will start the development web server and run the application at the following URL:

http://localhost:4200/

Conclusion

We discussed how to easily create Material styles multiple selection drop down using the ngx-mat-select-search library. This package supports a wide variety of features like search control, checkbox, labels, server-side population of options etc.

 

 

Leave a Comment

Your email address will not be published. Required fields are marked *