Reputation: 514
I have a search bar where you type employee name and it should return the name based on a filter. I have a nested JSON object (as shown below) where I need to drill into the object to access the employee's names in the array.
You can see the multiple options I tried to implement (they are commented out)
My problem is the code is not filtering the names and returning all the names not the names searched for. I get this error TypeError: Cannot read property 'filter' of undefined
The following code works to access the employee names in another component:
{test.map((result) => (result.details.map((innerArr) =>
<h5>{innerArr.employee}</h5>
)))}
how can I implement the above in the below code
const SearchByEmpComp = () => {
const [company, setCompany] = useState([
{
"company": "HIJ",
"_id": "610aeaec618ac5902c466541",
"details":
[
{
"employee": "Lesley Peden",
"notes": "Lesley's note",
"_id": "610aeaec618ac5902c466542"
},
{
"employee": "Wayne Smith",
"notes": "Wayne's note",
"_id": "610aeaec618ac5902c466543"
}
],
},
{
"company": "ABC",
"_id": "61003ff8e7684b709cf10da6",
"details":
[
{
"employee": "David Barton",
"notes": "some note!!",
"_id": "610aebb2618ac5902c46654e"
}
],
}
]);
//below code does not work
//attemp 1
const test = company.filter((r) =>
r.details.map((innerArr) => {
return innerArr.employee.toLowerCase().includes
(searchField.toLowerCase());
})
);
//attemp 1
// const test = company.map((el) => {
// return {...element, detail: element.detail.filter((details) =>
// details.employee.toLowerCase().includes
// (searchField.toLowerCase()))}
// })
//attemp 2
// const test = company.filter((res) => {
// return res.details.map((innerArr) =>
// innerArr.employee.toLowerCase().includes
// (searchField.toLowerCase()));
// });
//attemp 3
// const test = company.filter((comp) =>
// comp.details.employee.toLowerCase().includes(searchField.toLowerCase())
// );
const deatils = () => {
if (searchShow)
return <EmpDetailsByName test={test} />
}
};
return (
<>
<FormControl
type="search"
placeholder="Type Customer Name Here"
/>
<div>
<Button
onClick={handleClick}
>
Enter
</Button>
<div>{deatils()}</div>
</div
);
};
code to render names
const EmpDetailsByName = ({ test }) => {
return (
<>
{test.map((result) =>
(result.details.map((innerArr) =>
<h5>{innerArr.employee}</h5>
)))}
</>
);
};
export default EmpDetailsByName;
Upvotes: 2
Views: 3441
Reputation: 11037
In addition to Werlious's answer, if you are looking for the companies to still be included, then you can map as shown here. The first mapping will still return companies where all the employees have been filtered out. The second mapping will filter out companies without any details.
The third is a more modern approach to returning only the employees. But there are countless variations to use for that.
const company = [
{
company: "HIJ",
_id: "610aeaec618ac5902c466541",
details: [
{
employee: "Lesley Peden",
notes: "Lesley's note",
_id: "610aeaec618ac5902c466542",
},
{
employee: "Wayne Smith",
notes: "Wayne's note",
_id: "610aeaec618ac5902c466543",
},
],
},
{
company: "ABC",
_id: "61003ff8e7684b709cf10da6",
details: [
{
employee: "Lesley Peden",
notes: "some note!!",
_id: "610aebb2618ac5902c46654e",
},
],
},
];
const searchField = "les";
//attemp 1
const test = company.map((element) => {
return {
...element,
details: element.details.filter((details) =>
details.employee.toLowerCase().includes(searchField.toLowerCase())
),
};
});
console.log("test", test);
const test2 = company
.map((company) => {
let details = company.details.filter((detail) =>
detail.employee.toLowerCase().includes(searchField.toLowerCase())
);
if (!details.length) {
return null;
}
return { ...company, details };
})
.filter(Boolean);
console.log("test2", test2);
// Modern browser version of filtering to only the employees :)
const test3 = company.flatMap((company) =>
company.details.filter((detail) =>
detail.employee.toLowerCase().includes(searchField.toLowerCase())
)
);
console.log("test3", test3);
Upvotes: 5
Reputation: 594
I don't know how your filter is applied (what is it even filtering? Companies? Ids?), but really the search function should be its own little snippet as comments have suggested.
function SearchJsonForName(json,name) {
let result = []
for(company of json) {
for(employee of company.details) {
if(employee.name.match(name)) result.push(employee.name);
}
}
return result
}
That should get you started. If you need to apply a filter (maybe filtering companies?), you should apply it before you search the array (Or modify the function to take the filter as well ;>).
For a version that modifies the array in place:
function FilterByName(json,name) {
return json.map(company => {
let result = company.details.filter(employee =>
employee.name.match(name)));
return result.length > 0 ? {...company,details:result} : false;
}).filter(good => good);
};
Upvotes: 1
Reputation: 554
So I have a simple solution using Regex,
employeeArray = [
{
company: "HIJ",
_id: "610aeaec618ac5902c466541",
details: [
{
employee: "Lesley Peden",
notes: "Lesley's note",
_id: "610aeaec618ac5902c466542",
},
{
employee: "Wayne Smith",
notes: "Wayne's note",
_id: "610aeaec618ac5902c466543",
},
],
},
{
company: "ABC",
_id: "61003ff8e7684b709cf10da6",
details: [
{
employee: "David Barton",
notes: "some note!!",
_id: "610aebb2618ac5902c46654e",
},
],
},
];
// Set the state of the search string using state
let searchUser = "Les";
// converting the search string to regex
let convertedName = new RegExp(`.*${searchUser}.*`);
searchResults = employeeArray
.map((element) => {
return {
...element,
details: element.details.filter((employee) => {
// Filtering based on the Regex
return convertedName.test(employee.employee);
}),
};
})
// filtering based on the length of the data array length
.filter((element) => element.details.length > 0);
console.log(searchResults);
Explanation : So as per your condition,
Array.map
, we first apply a high level map to the Array directly, an then we focus on the inner details array and apply a filter for that also, And I have made that return a boolean based on the presence of the data,OUTPUT FOR SEARCHSTRING SET TO "LES"
[
{
company: 'HIJ',
_id: '610aeaec618ac5902c466541',
details: [
{
employee: 'Lesley Peden',
notes: "Lesley's note",
_id: '610aeaec618ac5902c466542'
}
]
}
]
This will help you bring out all he suggestions for a given name. An Array[Objects]
Upvotes: 1
Reputation: 6348
I made an example on how could you filter the json using a input text
Take a look at the use of states and how to access the companies
Upvotes: 1