Implementing Search In DropDown Field In Angular Using NgxMatSelectSearch

Introduction

In Angular, we are using the <mat-select> component of Angular Material to implement drop-downs. <mat-select> is the form control for selecting a value from a list of available options. 
We will generally use <mat-select> form control in our forms to implement drop-downs. We can give a list of options using <mat-option>. We can also use native <select> and <option> elements inside <mat-form-field> using matNativeControl attribute with the <select> element. <mat-select> should be use inside of <mat-form-field> component. 
<mat-form-field> is a component which is used as a wrapper for various Angular Material components. 

Now we will see an example where we implement drop-downs using both <mat-select> and native <select> element.

Both <mat-select> and native <select> elements should be used inside <mat-form-field>. <mat-option> and <option> has value as a property to set the value which user has selected from the drop-down list. 

<label>Country</label>
<mat-form-field>
    <mat-select>
    <mat-option value="India">India</mat-option>
    <mat-option value="China">China</mat-option>
    <mat-option value="Japan">Japan</mat-option>
  </mat-select>
</mat-form-field>

<label>State using native </label>
<mat-form-field>
  <select matNativeControl>
    <option value="Rajasthan">Rajasthan</option>
    <option value="Karnataka">Karnataka</option>
  </select>
</mat-form-field>

We will get the drop-downs using both ways. Now we will see how we can implement search in drop-downs.

Implementing Search In Drop-down 

We will use NgxMatSelectSearch to search the matSelect options. It is a component that will provide input for searching options available in the <mat-select> component of the Angular Material. We will see how to implement this in our Angular project for all the drop-downs.

Install NgxMatSelectSearch in our project

Write the below command to install and save the same in package.json file.

npm install ngx-mat-select-search --save

After installation, make an entry in the app.module.ts file in the import array section as follows. You need to make an entry in all the feature modules as well where you are using NgxMatSelectSearchModule. 


import { MatFormFieldModule, MatSelectModule } from '@angular/material';
import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';
@NgModule({
  imports: [
    ReactiveFormsModule,
    BrowserAnimationsModule,
    MatSelectModule,
    MatFormFieldModule,
    NgxMatSelectSearchModule
  ],
})
export class AppModule {}

Now we will go to our app.component.html file where we already have a drop-down for selecting user roles while creating a customer in our application. We are using [(ngModel)] here for two-way data binding. We have used *ngFor directive for displaying all the roles in the drop-down. <mat-option> has a value property to set the value for the user-selected option. The [value] property has the role name to be set as the value of the roleName. The selected role name gets assigned to the roleName in the [(ngModel)].

     <div>
            <label>Select User Role</label>
              <mat-form-field >
                <mat-select #roleName="ngModel" [(ngModel)]="roleName"  name="userRole">
                  <mat-option *ngFor="let role of roles" [value]="role.name">
                    {{role.name}}
                  </mat-option>
                </mat-select>
              </mat-form-field>
 </div>

We will implement a search here in template-driven forms as follows. We have used the  
<ngx-mat-select-search> component with [(ngModel)]. We can use the (ngModelChange) event of this element to filter the options. 

  • We can placeHolderLabel to show the placeholder label text.
  • To define what label to show when there is no item after filtering, we can use noEntriesFoundLabel.

   <div>
            <label>Select User Role</label>
              <mat-form-field>
                <mat-select #roleName="ngModel" [(ngModel)]="user.roleName" name="userRole">
                    <ngx-mat-select-search [(ngModel)]="searchCtrl" [placeholderLabel]="'Search...'"
                      [noEntriesFoundLabel]="'Not found'" name="search"></ngx-mat-select-search>
                    <mat-option *ngFor="let role of roles" [value]="role.name">
                    {{role.name}}
                  </mat-option>
                </mat-select>
              </mat-form-field>
 </div>

Now our job is not done here. We need to apply filter in <mat-option> *ngFor loop. We will create a custom pipe stringFilterBy as shown below. In this pipe we will pass searchText which is the [ngModel)] of <ngx-mat-select-search> element. fieldName is the other argument to know on which field or key we want to filter our array of objects. In our case we have the role name as our filter key. It can be anything depending on the requirement such as id, color, name, etc. For an array of objects, we can use the below StringFilterBy pipe.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'stringFilterBy'
})
export class StringFilterByPipe implements PipeTransform {

  transform(arr: any[], searchText: string,fieldName?:string): any[] {
    if (!arr) return [];
    if (!searchText) return arr;
    searchText = searchText.toLowerCase();
    return arr.filter((it:any) => {
      if(typeof it == 'string'){
        return it.toLowerCase().includes(searchText);
      }else if(typeof it == 'number'){
        return it.toString().toLowerCase().includes(searchText);
      }else{
        return it[fieldName].toLowerCase().includes(searchText);
      }
      
    });
  }
  
}

Now we use this pipe in our <mat-option> element. We will pass two arguments. One is SearchCtrl which is the searchText on which our list should get filtered. The other is 'name' which is the key to which role array of objects should be filtered. 

 <div>
            <label>Select User Role</label>
              <mat-form-field >
                <mat-select #roleName="ngModel" [(ngModel)]="user.roleName"  (ngModelChange)="onChange()"
                    (selectionChange)="onSelectionChange($event)" name="userRole">
                    <ngx-mat-select-search [(ngModel)]="searchCtrl" [placeholderLabel]="'Search...'"
                      [noEntriesFoundLabel]="'Not found'" name="search"></ngx-mat-select-search>
                  <mat-option *ngFor="let role of roles |stringFilterBy:searchCtrl:'name'" [value]="role.name">
                    {{role.name}}
                  </mat-option>
                </mat-select>
              </mat-form-field>
 </div>

Check how we used custom-pipe stringFilterBy in the above example. Suppose we want to filter roles array of the object on role id instead of the name. Then we will pass the second argument fieldName as id as shown below.

 <mat-option *ngFor="let role of roles |stringFilterBy:searchCtrl:'id'" [value]="role.name">
     {{role.name}}
</mat-option>            
Doing above steps, we will be able to see the search in drop-downs.

Comments

  1. Thanks, concise and easy. Just what I needed!

    ReplyDelete


  2. {{item.item_text}}


    first time when we click to open the select inside the search undefined is there
    is there any soution for the same ?

    your help will be a good motivation to ahead and using this plugin
    thanks in advance

    ReplyDelete
    Replies
    1. just initialize searchCtrl with null or empty string

      searchCtrl = '';

      Delete
  3. #roleName="ngModel" [(ngModel)]="user.roleName" what is this "user.roleName"and #roleName..

    ReplyDelete
    Replies
    1. In template-driven forms, if we want to apply validation or want to have access to the underlying form object. We will use #roleName="ngModel". Now roleName is reference for the corresponding form control object.

      Delete
  4. (ngModelChange)="onChange()"
    (selectionChange)="onSelectionChange($event)"
    what is to write in ts file,
    please attach workign example same as above things,html, ts files

    ReplyDelete
    Replies
    1. Hi. The following code has nothing to do with implementing search in drop-downs. We can remove this piece of code too. You can write any custom code according to the requirement in ngModelChange and selectionChange event emiiters. These
      (ngModelChange)="onChange()"
      (selectionChange)="onSelectionChange($event)"

      Delete
  5. does this work with reactiveforms?

    ReplyDelete
    Replies
    1. Yes this works with reactive forms as well. Refer the below link for checking the implementation in reactive forms.
      www.aanchalgarg.com/2020/05/implementing-search-in-dropdown-using.html

      Delete
  6. Thank you very much Aanchal Grag you made my day!!!!!!!

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete

Post a Comment