@ng-select
filter, we have a requirement to show only those results which have all of the words( or only a part of it ) typed in the search field. These term keywords can be separated by a space.
[searchFn]
property. This input property takes in a function to return the term
(Typed by user) and items
(All items of the available in the data set) of the select.[searchFn]
property on the <ng-select/>
element directive.@ng-select
package and overview of its features, check this previous post.<ng-select>
element with some input property options:<ng-selectÂ
[items]="userList"Â
[(ngModel)]="selectedUser"
bindLabel="search_label" Â
bindValue="id"
[searchFn]="customSearchFn">
    <ng-template ng-option-tmp let-item="item">
Name: {{item.name}} ({{item.username}}) <br />
<small>Contact: {{item.email}},{{item.phone}}</small> <br />
<small>Address: {{item.address.street}}, {{item.address.suite}}, {{item.address.city}},
{{item.address.zipcode}}</small> <br />
<small>Site:Â {{item.website}}</small>
</ng-template>
</ng-select>
In the above HTML template, we have some required properties
[items]
: Object of items to show in the select options.
[(ngModel)]
: Model can be used to set default items or to fetch the selected values of ID’s or any property which we define in the bindValue
.
[searchFn]
: As we already discussed, this property is optional and used if we want to override the search algorithm. By default, it ng-select only filter out the property of the object which we define in the bindLabel
property.
<ng-template>
: The NgTemplate element tag is used to customize the select option look and feel. To show multiple values from the Object, we used ng-template wrapper.
Up to here, there is nothing cool and we are just using a simple implementation of the ng-select in the component.
let’s add the magic function in the component class to customize the filter behavior and make it smarter for a complex dataset with multiple properties.
Using this method a user will be able to filter out the required information.
Quickly update the component class with the following code, after that we will discuss it in more detail.
// app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'ng-select-filter-demo';
userList = [];
selectedUser: number;
constructor(
private http: HttpClient
) { }
ngOnInit() {
this.getUsersList();
}
// Fetching users data
getUsersList() {
this.http
.get<any>('https://jsonplaceholder.typicode.com/users')
.subscribe(response => {
this.userList = response.map(o => {
o.search_label =
` ${o.id} ${o.name} ${o.username} ${o.email} ${o.phone} ${o.website} ${o.phone} ${o.address.street} ${o.address.suite} ${o.address.city} ${o.address.zipcode}
`
return o
});
console.log(this.userList);
}, error => {
console.log(error);
});
}
customSearchFn(term: string, item: any) {
term = term.toLowerCase();
// Creating and array of space saperated term and removinf the empty values using filter
let splitTerm = term.split(' ').filter(t => t);
let isWordThere = [];
// Pushing True/False if match is found
splitTerm.forEach(arr_term => {
let search = item['search_label'].toLowerCase();
isWordThere.push(search.indexOf(arr_term) != -1);
});
const all_words = (this_word) => this_word;
// Every method will return true if all values are true in isWordThere.
return isWordThere.every(all_words);
}
}
In the above code, we have two functions. The getUsersList() is fetching remote results using HTTP’s get method which is are feeding to the userList
.
Here we are doing something strange by using the map()
function.
Actually we are creating a new property search_label
where you can add the properties you want to filter out for an item. So this property will play a major role in our search logic for the customSearchFn
function.
Going through each section of function, it returns the term
having string types by a user and item
containing each record to be shown in the options.
First, we will split
the term by spaces and remove every item which is empty using the filter
.
let splitTerm = term.split(' ').filter(t => t);
After that, we are using the forEach
method to parse each value typed by the user and matching it with the item’ssearch_label
property having all values using indexOf
.
    splitTerm.forEach(arr_term => {
      let search = item['search_label'].toLowerCase();
      isWordThere.push(search.indexOf(arr_term) != -1);
    });
isWordThere
array tracks for the words which are there in the item’s search_label
property.every
method.Conclusion
@ng-select
package is very popular module to add select boxes with many features like virtual scroll, checkboxes, single multiple selections. In this post, we discussed how to customize filter login so that a user can filter not only from multiple properties but also simultaneously by separating queries with space.
Leave a Reply