Reputation: 1059
I'm iterating a list of jobs and there's a search implemented on this list. Search is working but now it only filters list based on one field.
Here's my list:
<ion-card *ngFor="let job of allJobs | search : searchTerm">
<ion-grid>
<ion-row>
<ion-col>
<div>
<span> {{job.day | uppercase}}</span>
<span> {{job.month | uppercase}}</span>
</div>
</ion-col>
<ion-col>
<div>
<span>{{job.time}}</span>
<span>{{job.name}}</span>
</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>
I made a pipe for implementing search. Here's the code for it.
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return it.name.toLowerCase().includes(terms); // only filter name
});
}
Now the list gets filtered only based on the name
field. I wanna filter the list based on day
, month
and time
as well.
Can anyone tell me how to make this happen?
Sample Data for Jobs. Jobs is an array of objects
[
{
"id":10,
"day":"Monday",
"month":"June",
"time":"10",
"name":"John",
"email":"[email protected]"
},
{
"id":11,
"day":"Tuesday",
"month":"May",
"time":"12",
"name":"Jane",
"email":"[email protected]"
},
{
"id":12,
"day":"Friday",
"month":"June",
"time":"16",
"name":"",
"email":"[email protected]"
},
{
"id":13,
"day":"Tuesday",
"month":"August",
"time":"21",
"name":"",
"email":"[email protected]"
},
{
"id":14,
"day":"Saturday",
"month":"December",
"time":"12",
"name":"Sam",
"email":"[email protected]"
},
]
And searchTerm
is just a string.
As you can see, there are more fields in the sample data than the one displayed in the HTML but I'm trying only to search for the fields that are displayed in the HTML. Some fields can have null values (for eg. name
in the sample data has two null values)
I tried the solutions already provided but none of them are working for my requirement.
P.S: Read somewhere that pipes are not the best option to do functionality like this. I'm ready to implement this logic in the class as well.
Upvotes: 3
Views: 551
Reputation: 79
filterItems(param: any): void { let val: string = param;
if (val) {
if (val.trim() !== '') {
this.filterItemsList = this.items.filter((data) => {
console.log(data.category);
return data.category.toLowerCase().indexOf(val.toLowerCase()) > -1
|| data.products.some(product => product.code.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
}
it's working perfect
Upvotes: 0
Reputation: 1897
Try this code.. it's pretty simple.
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
terms = terms.trim();
return items.filter(it => {
if (it.day) {
return it.day.toLowerCase().includes(terms);
}
if (it.month) {
return it.month.toLowerCase().includes(terms);
}
if (it.time) {
return it.time.toLowerCase().includes(terms);
}
if (it.name) {
return it.name.toLowerCase().includes(terms);
}
});
}
If your JSON has null values, you can replace it with an empty string using the following code:
items = JSON.parse(JSON.stringify(items).replace(/null/g, '""'));
Upvotes: 3
Reputation: 6511
Try combining your includes
with the logical or-operator (||
):
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
return items.filter(it => {
return it.name.toLowerCase().includes(terms) ||
it.day.toLowerCase().includes(terms) ||
it.month.toLowerCase().includes(terms) ||
it.time.toLowerCase().includes(terms)
});
}
This statement will return true if any of the includes
returns true. So basically any item which name
, day
, month
or time
contains the searchterm will be returned by the pipe.
This solution assumes that name
, day
, month
and time
are not null or undefined. But I'm assuming that is okay as your sample data suggests null values will be empty strings(""
). If my assumption is not correct you'll have to check if the values are assigned, before accessing them.
Upvotes: 4
Reputation: 499
Inside your transform method of your search pipe, apply filters on all the fields you want to apply filter on. Following will search for all keys in the object:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return keys(it).reduce((prev, key) => {
return prev || key.toLowerCase().includes(term);
}, false);
});
}
If keys or Object.keys are not working, use the following code instead of reduce function:
...
let bInclude = false;
for(let key in it){
bInclude = bInclude || key.toLowerCase().includes(term);
}
return bInclude;
...
Upvotes: 1
Reputation: 37
This dont work because the includes
dont test for multiple term cases. You didnt say whats inside the items Array
but if it is a String you could do this:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
//if it is something like "Programmer 07 November 12:00PM"
var informations = it.split(' '); //["Programmer", "07" ,"November" ,"12:00PM"]
var termArray = terms.split(' ');
var rightResult = true;
for (var index in termArray) {
if !(informations.include(termArray[index])) {
rightResult = false;
}
return rightResult;
});
}
Upvotes: 1