Filter on multiple columns using one pipe angular 2
Solution 1
Here is a solution using the object passed as multiple columns filter. I found it more convenient then passing a 2D array:
@Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(items: Array<any>, filter: {[key: string]: any }): Array<any> {
return items.filter(item => {
const notMatchingField = Object.keys(filter)
.find(key => item[key] !== filter[key]);
return !notMatchingField; // true if matches all fields
});
}
}
Having an array of objects with multiple columns:
this.people = [
{name: 'John', age: 27, sex: 'male'},
{name: 'Lara', age: 21, sex: 'female'},
{name: 'Rick', age: 29, sex: 'male'},
{name: 'Eva', age: 27, sex: 'female'},
{name: 'Mike', age: 27, sex: 'male'}
];
And a filter:
this.peopleFilter = {age: 27, sex: 'male'};
Use it like:
<div *ngFor="let person of people | filter: peopleFilter;"></div>
As a result, two people are matching our criteria: John and Mike.
Here is the working plunker: Multiple columns filter pipe demo.
Solution 2
Here is what I did with Angular 8:
Goal: Search on multiple properties say "Property1" and "Property2" from a list of items for a given keyword:
app.module.ts:
......
import { MyFilterPipe } from './shared/pipes/my-filter.pipe';
@NgModule({
declarations: [
...
MyFilterPipe
],
imports: [
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Pipe: content-filter.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'myFilter'
})
export class MyFilterPipe implements PipeTransform {
transform(items: any[], keyword: any, properties: string[]): any[] {
if (!items) return [];
if (!keyword) return items;
debugger;
return items.filter(item => {
var itemFound: Boolean;
for (let i = 0; i < properties.length; i++) {
if (item[properties[i]].toLowerCase().indexOf(keyword.toLowerCase()) !== -1) {
itemFound = true;
break;
}
}
return itemFound;
});
}
}
component:
<input type="search" class="form-control filter-list-input" placeholder="Filter"
aria-label="Filter" name="search" [(ngModel)]="searchText" >
<div *ngFor="let itemof myItems | myFilter:searchText:['Property1', 'Property2']; let i = index">...
</div>
component.ts:
export class MyListComponent implements OnInit {
...
searchText: string;
Solution 3
Replace Your code as below,
export class DataFilterPipe implements PipeTransform {
transform(value: Item[], field: string, args: string): Item[]{
let filter: string = args ? args.toLocaleLowerCase() : null;
return filter ? value.filter((item : Item) =>
Item[field].toLocaleLowerCase().indexOf(filter) != -1) : value;
}
}
In Html page,
<tbody *ngFor="let item of items | dataFilter : columnName : value ">
Solution 4
I am assuming that you have an array with columns like this:
[{col1:"col1",col2:"col2",col3:"col3"}]
I have also omitted all type-checkin, null-pointers, and error-handling. The current solution is an example I tried with the array:
myData:Array<any> = [{col1:"a",col2:"b",col3:"cadd"},
{col1:"abba",col2:"bobba",col3:"cadd"},
{col1:"abba",col2:"bobba",col3:"cool"},
{col1:"a",col2:"bobba",col3:"cool"}];
and the pipe:
@Pipe({
name: 'dataFilter'
})
export class DataFilterPipe implements PipeTransform {
transform(value: any, args?: any): any {
return value.filter(item =>{
var matchesAll = true;
for(var i = 0; i<args.length; i++){
// check if your data contains the column and the value defined in args.
if(item.hasOwnProperty(args[i][0]) && item[args[i][0]]==args[i][1]){
continue;
}else{ // at least one column did not match,
matchesAll = false;
}
}
return matchesAll;
});
}
}
You can then call
dataFilter.transform(myData,[["col1","abba"],["col2","bobba"],["col3","cool"]]);
in order to get one result, which is row number 3 after transformation: [{col1:"abba",col2:"bobba",col3:"cool"}]
.
Note: You may have to adjust the names of the columns in my example to make it work with your code.
EDIT: With this solution, you can also pass arbitrary number of columns.
e.g dataFilter.transform(myData,[["col3","cool"]]);
which will result in the two last rows (from my example) after transformation:
[{col1:"abba",col2:"bobba",col3:"cool"},{col1:"a",col2:"bobba",col3:"cool"}]
EDIT: after comment stating that the code is not working, I provided a plunkr of the example above: https://plnkr.co/edit/VdpGJWyzWUVFzYNDSz1g
Jeeten Parmar
Updated on May 21, 2021Comments
-
Jeeten Parmar almost 3 years
I am trying to filter
Array
data based on multiple columns using only onePipe
. Right now, It filters first column value. Please check my below code and help me to sort this out.My Code:
@Pipe({ name: "dataFilter", pure: false }) export class DataFilterPipe implements PipeTransform { transform(value: Array<any>, filter: any[]) { if (!filter) { return value; } else if (value) { return value.filter(item => { for (var i = 0; i < filter.length; i++) { if (filter[i][1] == undefined) { return true; } else if ((typeof item[filter[i][0]] === 'string' || item[filter[i][0]] instanceof String) && (item[filter[i][0]].toLowerCase().indexOf(filter[i][1]) !== -1)) { return true; } return false; } }); } } }
I am passing data like
dataFilter : [['column1',value1],['column2',value2],['column3',value3]]
.