Blog | How to create a Custom Filter pipe in Angular Typescript
-
Home
-
Blog
How to create a Custom Filter pipe in Angular Typescript
Posted on Tuesday, June 2, 2020
In my workplace, I had to implement the search functionality for the list. So, later on, I found out about creating a custom pipe to implement it. The pipe will help us to prepare data to be displayed in the template. In our case, it will help to filter array.
How it works:
- First of all, we will have an array of objects.
- We create a filter pipe which accepts an argument.
- This argument will filter through each object in array comparing against the object's properties values.
- Those objects will be return if any of its properties values matches the argument.
Let's get started:
Objective: To create a custom Angular pipe in order to filter the given array by any properties.
Steps
- First of all, we create a custom pipe.
- Command:
- ng generate pipe --spec=false filter
- This will create a file called filter.Pipe.ts and update app.module.ts by including a FilterPipe class to declaration list as following:
- The content of the filter.pipe.ts:
//filter.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any, args?: any): any {
return null;
}
}
- Here,
- We see a @Pipe décorator that defines angular pipe with a name property.
- In the transform method, the first parameter value receives the data we provide to the pipe formats.
- The second argument args is an optional parameter that we can provide value. In this scenario, we use second argument to filter the value (data) that we receive i.e. data is the array we receive. We change the args? to searchText? (giving more meaningful name).
- If the searchText is null or undefined or empty, return the provided value (array data). Otherwise we filter the array through given searchText parameter.
- This is the modifed content of the filter.pipe.ts:
//filter.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any, searchText?: any): any {
//return value if searchText is null, empty or undefined
if(!searchText) {
return value;
}
//matchValue is called for every single object contained in value array
//If matchValue method returns false for the object, that object will be skipped and not be collected and returned by filter
return value.filter((data) => this.matchValue(data,searchText));
}
//return true if searchText matches any of the object property value
matchValue(data, searchText) {
return Object.keys(data).map((key) => {
return new RegExp(searchText, 'gi').test(data[key]);
}).some(result => {
return result==true;
});
}
}
- Explanation of the code:
- Array.filter()
- The filter() method creates a new array with all elements that pass the test implemented by the provided function.
- Filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values that returns true. i.e.
It calls matchValue function for every object in the array.
- Here, we pass data as a parameter to filter() array which represents object in the array. The provided function is a matchValue() where we pass data and searchText.
- Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
- Object.keys()
- The keys() method returns an array of the property names (as a string) of the given object.
- So here, it will the return list of property name of the data object that is passed as a parameter.
- For an example, if the menu is the object and it's properties are id, name, description and price. This will return ["id", "name", "description","price"]
- Array.map()
- The map() method calls the provided function once for each element in an array, in order.
- From Object.keys(), we get an array of property names. So, it will execute as Array of the property names.map()
- The map() method creates a new array populated with the results of calling a provided function.
- Right now we will be calling a callback function which returns Boolean values that we get from test() method of new RegExp() i.e. RegularExpression. A regular expression with searchText pattern will be created which will be used for global matching and case-insensitive matching for the property value.
- The test() method returns true if the property value i.e. data[key] has the value that matches the searchText otherwise return false.
- So, the map() method will collect list of either true or false values which is equivalent to the number of properties in the object.
- Array.some()
- The some() method returns either true or false whether at least one element in the array passes the test implemented by the provided function.
- Array.map() will contains list of true or false value, so some() method will return true if the provided function returns true for at least one element in the array.
- So, back in the filter array, it will receive either true or false for an object. If true is return, filter will keep it otherwise ignore it. Hence, the filtered array will be displayed in the template.
- How to use in the template:
-
//template.component.html
<input type="text" [(ngModel)]="textValue" />
<tr *ngFor="let item of menuList | filter: textValue">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.desrciption}}</td>
<td>{{item.price}}</td>
</tr>
//textValue is the variable you defined in the template.component.ts and here you do two-way binding with the input element.
//After the vertical bar, filter is the name of pipe we created i.e. filter.pipe.ts
//@Pipe({
// name: 'filter' //this is the name of the pipe
//})
References: