Reputation: 259
I have state data that looks like this:
state = {
search: “”
tagValue: “”
data: [
{
id: 1,
fName: "Henry",
lName: "Jones"
email: “[email protected]”,
gpa: “3.6”
tag: [
"hello", "bye"
]
},
{
fName: "Jeffrey",
lName: "Johnston”,
email: “[email protected]”,
gpa: “2.6”,
tag: [
"hello", "bye"
]
},
{
fName: "Henry",
lName: "Jones"
gpa: “1.9”
tag: [
]
}
]
}
I've figured out how to filter the data array based on user input by doing:
let studentListFilter = this.state.data.filter((student) => {
return (
student.firstName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1 ||
student.lastName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1
}
and then returning studentListFilter in my render method. search is a state value updated based on user input. But I'm having trouble figuring out how to compare values located within an array, specifically tag in this case, to user input.
I've tried doing this to no avail:
let studentListFilter = this.state.data.filter((student) => {
return (
student.fName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1 ||
student.lName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1 ||
student.tag.map(
(individualTag) =>
individualTag
.toLowerCase()
.indexOf(this.state.tagValue.toLowerCase()) !== -1
)
);
});
Any help would be great
Upvotes: 1
Views: 81
Reputation: 202864
One of the issues is that when checking if any of the string values includes the filtering input is that all strings include the empty string.
console.log("test".indexOf('') !== -1);
console.log("test".includes(''));
So the problem arises when you have two filtering inputs and assume when they apply to the data. Because the above then one of your conditions is always true if one of the inputs is empty and thus the data is never filtered.
Filter logic:
this.state.data
.filter(student => {
if (this.state.search && this.state.tagValue) {
return (
(student.fName.toLowerCase().includes(this.state.search) ||
student.lName.toLowerCase().includes(this.state.search)) &&
student.tag.some(tag => tag.toLowerCase().includes(this.state.tagValue))
);
}
if (this.state.search) {
return (
student.fName.toLowerCase().includes(this.state.search) ||
student.lName.toLowerCase().includes(this.state.search)
);
}
if (this.state.tagValue) {
return student.tag.some(tag =>
tag.toLowerCase().includes(this.state.tagValue)
);
}
return true;
})
As can be seen there is a lot of repetition, a bit more DRY approach:
{this.state.data
.filter(({ fName, lName, tag }) => {
const includesName = [fName.toLowerCase(), lName.toLowerCase()].some(
name => name.includes(this.state.search)
);
const includesTag = tag.some(tag =>
tag.toLowerCase().includes(this.state.tagValue)
);
if (search && tagValue) {
return includesName && includesTag;
}
if (search) {
return includesName;
}
if (tagValue) {
return includesTag;
}
return true;
})
Upvotes: 1
Reputation: 3731
basically you can use some for your use case:
something like this:
let studentListFilter = this.state.data.filter((student) => {
const matchFirstName = student.fName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1;
const matchLastName = student.lName
.toLowerCase()
.indexOf(this.state.search.toLowerCase()) !== -1
// will return true if one of your tags match the search
const someFnCB = (individualTag) => {
return individualTag.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1
};
const matchTag = student.tag.some(someFnCB)
return matchFirstName || matchLastName || matchTag;
});
Upvotes: 0