I have modal in a React app that renders a list of items with a list of nested values and a search bar. When the user types into the search bar, I need to be able to match that input to an item in the list and show the exact path to that match.
For example, my data looks like:
const dataList = [
{
label: 'Foo',
value: 'foo',
subItems: [
{
label: 'Sub bar 1',
value: 'sub_bar_1',
subItems: [
{ label: 'Nested baz 1', value: 'nested_baz_1' },
{ label: 'Nested baz 2', value: 'nested_baz_2' },
],
},
{
label: 'Sub bar 2',
value: 'sub_bar_2',
},
],
},
{
label: 'Bar',
value: 'bar',
subItems: [],
},
];
And given the query string, Nested baz 2
, I’d expect the output to be:
const filteredList = [{
label: 'Foo',
value: 'foo',
subItems: [
{
label: 'Sub bar 1',
value: 'sub_bar_1',
subItems: [
{ label: 'Nested baz 2', value: 'nested_baz_2' },
],
},
],
}];
I’ve tried multiple iterations of a recursive function and old-school for
loops but nothing can give me the exact path to the object that matches my query string.
Is there anything I can change in this current implementation to get the desired output?
const filterItems = (
options: Option[],
query: string
): Option[] => {
return options.filter((option) => {
if (option.label.toLowerCase().includes(query.toLowerCase())) {
return true;
}
if (option.subItems) {
return filterItems(option.subItems, query).length > 0;
}
return false;
});
};
const filteredItems = useMemo(() => {
return filterItems(options, query);
}, [options, query]);
[EDIT]: update so that recursive call was calling the right function
2
Answers
You can achieve this with the below
The problem with your implementation is that you lose the filtering you have applied here:
The filtered array is not retained: only the length serves to return false/true, but when it is
true
, you still have all thesubItems
. You need to create new objects when thesubItems
property is going to get a reduced array.You could combine
map
withfilter
, where you map either a new object with reducedsubItems
, orundefined
. Chain afilter
call to only retain the objects: