Implementing a search bar for filtering the options in the select-dropdowns in Angular

Shafi Sahal
Geek Culture
Published in
5 min readSep 21, 2021

During one of my projects, it was needed to implement a select-dropdown for showing the countries with their respective dial codes and the user should be able to search through them. This was to make the mobile number in the right format.

Unfortunately, I came to know that Angular Materials does not provide that functionality. So, I thought if I could have a workaround using the matAutoComplete. I have seen some Github comments about the workaround but they were not powerful enough and were a bit complicated.

The issue has been addressed to the angular material team by many through a Github issue a long time ago. The team says they are looking for a solution and they will implement it and yeah they may have got more important problems to solve. You can check about the issue here: https://github.com/angular/material2/issues/5697

So as usual, I tried searching for libraries to do the work till the angular team implement the feature and I found a couple of them, but they were either too simple to be any powerful or were too complicated and verbose to be convenient.

That’s when I thought about trying to develop a library to solve this problem. I wanted to make it simple to use and yet it should be powerful and that’s what MatSelectSearch has become. So finally, there is a solution to this problem.

MatSelectSearch

npm link: https://www.npmjs.com/package/mat-select-search

MatSelectSearch is an Angular component providing functionality to search/filter MatSelect options of the Angular Material library which is simple to use and more powerful than any other library that aims to solve this problem currently. The search functionality is optimized too, that is MatSelectSearch is able to search through long lists faster than the current libraries for the same.

How to use it?

Install mat-select-search in your project

npm install mat-select-search

Import the mat-select-search into the app module. In case lazy loading is being used, import it into the particular module where you need the library.

Place the lib-mat-select-search component inside a mat-option of the mat-select.

There are two inputs to be passed to enable the search:

  • [list]
  • [searchProperties]

There is one event fired after filtering the mat-options

  • (filtered)

[list]

Pass the array to be filtered to the lib-mat-select-search through the [list] input.

[list]="countries"

[searchProperties]

Pass the properties which are to be searched to the [searchProperties] input. Now, here mat-select-search is providing a unique functionality that the other current libraries do not provide.

mat-select-search supports multi-property search. Consider a scenario where you have a list of countries as such:

[
{
name: "India",
dialCode: "+91",
code: "IN"
},
{
name: "Indonesia",
dialCode: "+62",
code: "ID"
},
..............and goes on

Now, suppose there is a use case where the search should happen not only by name but also with dialCode and code. So, even if the user types the dialCode of the country or the code of the country, the search should be happening. To enable this property in mat-select-search there is no extra overhead.

[searchProperties] receives an array of strings. The strings are the properties by which the search should happen. So, in case if the search should happen only by the name provide:

[searchProperties]="['name']"

If the search should happen by name, dialCode and code, just provide:

[searchProperties]="['name', 'dialCode', 'code']"

It’s as simple as that.

Now, the order by which the properties are provided matters a bit. If the properties are provided in the above manner, the search term ‘India+91’ will still give the correct result but not ‘+91India’. Consider the order if you got any particular use case where this matters. In most cases, it does not matter. So the order of the properties does not matter much.

(filtered)

(filtered) is an event that is fired after filtering the mat-options. Store this filtered array into another variable.

//Storing the filtered array in filteredCountries
(filtered)="filteredCountries = $event"

And that’s it. Now mat-select-search is ready and you can implement the search!!!

The [list] and [searchProperties] are the required inputs for the search to work. There are optional inputs too that provide some customization.

[clearSearchInput]

[clearSearchInput] is set to false by default. When set to true, the search bar will be cleared after the mat-select is closed so that when the mat-select is reopened the search bar will be empty.

[fixOnTop]

[fixOnTop] is set to false by default. When set to true, the search bar position is fixed on the top and it does not scroll with the mat-options, so it is visible even while scrolling.

So, why not set it to true by default?. It’s because the search bar never loses focus. So even if it is scrolled upwards and is not visible, just press any key and the search bar appears and the search happens. So, there is not necessarily a need to fix it on top. Especially for mobile devices, it is better to make it scroll, so the unwanted space is saved and a mat-option will be displayed in its place.

Also, if a user prefers scrolling rather than typing, the search bar is purely a waste of space. So, [fixOnTop] is set to false by default and if someone wants it to stay at the top, it’s still possible, just set [fixOnTop] to true.

[hasSelectAll]

[hasSelectAll] is set to false by default. When set to true, it provides functionality to have an option to select all the mat-options in the multiple select.

Also, provide a mat-option for ‘Select All’ and place it below the mat-option for lib-mat-select-search.

<mat-option>Select All</mat-option>

How to make MatSelectSearch work with formArray?

While working with formArray, it is not enough to just store a single filtered array. There should be a filtered array for each form.

Imagine a scenario where there are multiple forms and each one has a mat-select to select the country. With the same logic as above, the search will work perfectly for the mat-select whichever the user interacts with initially but while interacting with another mat-select, the value of the first mat-select will be gone. This is because the variable ‘filteredCountries’ is shared by all the mat-select.

So, to solve all these problems, make ‘filteredCountries’ a 2-d array and store the filtered array in the respective index of the ‘filteredCountries’.

If you liked this component or if it has been helpful to you in solving your problems, please star the repo: https://github.com/shafi-sahal/MatSelectSearch.

Contributions, feedback, and suggestions are always welcome.

You can download the library from here: https://www.npmjs.com/package/mat-select-search

--

--

Shafi Sahal
Geek Culture

Developer, adventure lover and a truth seeker. Like to write about topics from a unique perspective. Twitter: https://twitter.com/_shafisahal.