I have an requirement to build a search component which will filter data from the below data structure. The Data structure is as follows,
const data = {
details: {
Alex: {
name: 'ABC1',
icon: shopIcon,
content: [{
risk: 0,
name: 'basketball',
value: ["str1", "str2"]
},
{
risk: 0,
name: 'tennis',
value: []
}
]
},
Leon: {
name: 'ABC2',
icon: shopIcon,
content: [{
risk: 0,
name: 'Cricket',
value: ["str1"]
},
{
risk: 0,
name: 'swimming',
value: []
}
]
},
Harsha: {
name: 'ABC2',
icon: shopIcon,
content: [{
risk: 0,
name: 'baseball',
value: ["str1"]
},
{
risk: 0,
name: 'hockey',
value: []
}
]
}
}
}
I want to filter the content in above type data from both the keys in details and the name in content.
For Example:- if user type 'le' both the Alex and Leon data should display.
search Field Text :- "le"
output :-
Alex: {
name: 'ABC1',
icon: shopIcon,
content: [{
risk: 0,
name: 'basketball',
value: ["str1", "str2"]
},
{
risk: 0,
name: 'tennis',
value: []
}
]
},
Leon: {
name: 'ABC2',
icon: shopIcon,
content: [{
risk: 0,
name: 'Cricket',
value: ["str1"]
},
{
risk: 0,
name: 'swimming',
value: []
}
]
},
Search Text field :- ball
output :-
Alex: {
name: 'ABC1',
icon: shopIcon,
content: [{
risk: 0,
name: 'basketball',
value: ["str1", "str2"]
}]
},
Harsha: {
name: 'ABC2',
icon: shopIcon,
content: [{
risk: 0,
name: 'baseball',
value: ["str1"]
}]
}
I was only able to achieve the search only by one part. Either with the main key value or with the content name value. Was not able to achieve both at once. Here is the code that I used to achieve the search with the main key value. Any Explanation on what I am missing in here so that I can achieve search in both the places at once ?
Object.entries(data.details).filter((k) => {
let searchFieldText = searchText.toLowerCase();
if (searchFieldText === "") {
return k;
} else if (k[0].toLowerCase().includes(searchFieldText)) {
return k;
}
}).map(([keys, values]) => (
<>
<p>{values.name}</p>
{values.content.map((contents) => {
<p> {contents.name} </p>
})
</>
))
CodePudding user response:
If you want to search both the key value and the name in the content, you can do something like this:
Object.entries(data.details).filter((k) => {
let searchFieldText = searchText.toLowerCase();
if (searchFieldText === "") {
return k;
} else if (k[0].toLowerCase().includes(searchFieldText) || k[1].content.some(i => i.name.toLowerCase().includes(searchFieldText))) {
return k;
}
}).map(([keys, values]) => (
{ /* ... */}
))
CodePudding user response:
Why this method:
- Search for the match in
key
and name in the content array (value.content[].name
) - The hole process done in one loop
If you want an object
in return try this
const checkIncludes = (a, b) => {
return a.toLowerCase().includes(b.toLowerCase());
};
const output = Object.entries(data.details).reduce((a, b) => {
if (!searchText) {
a[b[0]] = b[1];
}
if (checkIncludes(b[0], searchText)) {
a[b[0]] = b[1];
}
if (b[1]?.content.some((e) => checkIncludes(e.name, searchText))) {
a[b[0]] = b[1];
}
return a;
}, {});
console.log(output);
// {
// Alex: { name: 'ABC1', icon: '', content: [ [Object], [Object] ] },
// Leon: { name: 'ABC2', icon: '', content: [ [Object], [Object] ] }
// }
If you want an array
in return try this
const checkIncludes = (a, b) => {
return a.toLowerCase().includes(b.toLowerCase());
};
const output = Object.entries(data.details).reduce((a, b) => {
b[1].key = b[0];
if (!searchText) {
a.push(b[1]);
}
if (checkIncludes(b[0], searchText)) {
a.push(b[1]);
}
if (b[1]?.content.some((e) => checkIncludes(e.name, searchText))) {
a.push(b[1]);
}
return a;
}, []);
console.log(output);
// [
// {
// name: 'ABC1',
// icon: '',
// content: [ [Object], [Object] ],
// key: 'Alex'
// },
// {
// name: 'ABC2',
// icon: '',
// content: [ [Object], [Object] ],
// key: 'Leon'
// }
// ]
Create react element
output.map((each) => (
<div key={each.key}>
<p>{each.name}</p>
{each.content.map((contents, i) => {
<p key={i}> {contents.name} </p>
})
</div>
))