Introduction
So let’s say you have a text input, and you want it to use it to filter on multiple properties of list items. How do you do this?
Our text input, for example:
<ion-searchbar [(ngModel)]="searchText" placeholder="Search items..."></ion-searchbar>
And the list before:
<ion-item-sliding *ngFor="let item of items" detail="true">
And after:
<ion-item-sliding *ngFor="let item of items | textFilter:searchText:['title', 'description']" detail="true">
So how do we get there? Let’s start by creating a pipe!
Pipes
So, what are pipes? From the Angular docs: “Pipes are simple functions to use in template expressions to accept an input value and return a transformed value.” Angular provides a bunch of built-in pipes, mostly to transform strings (though there’s the AsyncPipe which I have written about). Of course, we can make our own, and one that transforms an array of objects.
Text Filter
Let’s create the skeleton for our text filter pipe:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'textFilter'
})
export class TextFilterPipe implements PipeTransform {
}
Here we’re adding the name of the pipe and creating a class that implements PipeTransform
. Next, we’ll need to add a transform
function where all the magic happens.
Remember our requirement: filter a list of items by selected item properties. Our pipe should take in three inputs:
- The search text (
string
) - The list of items (
any[]
) - A list of item properties (
string[]
)
transform(items: any[], keyword: string, properties: string[]): any[] {
}
Next, let us deal with conditions where things are “empty”:
if (!items) { return []; }
if (!keyword) { return items; }
Now for the heart of the function - the filtering! If we are going to filter something, what function should we use? filter
, of course!
return items.filter(item => {
});
Remember, these items have properties. And we need to look through each property to determine if there’s a match to the text we have provided. So how might we do that? Let’s use the entries
method on each property for each item. Here’s a reference for that method.
let itemFound: boolean;
for (const [i, v] of properties.entries()) {
if (item[properties[i]].toLowerCase().indexOf(keyword.toLowerCase()) !== -1) {
itemFound = true;
break;
}
}
return itemFound;
Then we’re using the indexOf
method to search the string for an occurence of the keyword. If we find it, add it to the list of items found.
Put it all together and you get:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'textFilter'
})
export class TextFilterPipe implements PipeTransform {
transform(items: any[], keyword: string, properties: string[]): any[] {
if (!items) { return []; }
if (!keyword) { return items; }
return items.filter(item => {
let itemFound: boolean;
for (const [i, v] of properties.entries()) {
if (item[properties[i]].toLowerCase().indexOf(keyword.toLowerCase()) !== -1) {
itemFound = true;
break;
}
}
return itemFound;
});
}
}
Conclusion
Pipes are simple functions but can be made to do powerful things such as implmenting a filter by text, in only a few lines of code. This feature is immensely useful for the user, and on the software side we have maintainable way of doing it.
As a final review, let’s look at the textFilter
pipe applied in the template:
<ion-item-sliding *ngFor="let item of items | textFilter:searchText:['title', 'description']" detail="true">
And that’s it!