I'm trying to get store names from a nested array but I'm getting no results, everything works fine but when I type in the search bar and I get nothing (Image below). I can see the flatlist again once I delete what I typed in. I think the problem is with the data I'm returning from the filter. Here's what I did so far.
const Purchases = () => {
const extractKey = ({purchases}) => purchases.toString();
const [search, setSearch] = useState(content);
function _searchFilterFunction(searchText, data) {
let newData = [];
if (searchText) {
newData = content.filter(function (item) {
item.purchases.filter(function (i) {
const itemData = i.name.toUpperCase();
const textData = searchText.toUpperCase();
return itemData.includes(textData);
})
});
setSearch([...newData]);
} else {
setSearch([...data]);
}
}
return (
<View style={styles.container}>
<TextInput
style={styles.textInputStyle}
placeholder="Search by Store"
onChangeText={(value) => {
_searchFilterFunction(value, content);
}}
/>
<FlatList
data={search}
renderItem={renderItem}
keyExtractor={extractKey}
/>
</View>
);
}
and here's the array:
let content = [
{
date: 'September 8, 2012',
total: 754,
purchases: [
{
name: 'Virgin Megastores',
time: '12:24',
price: 432,
icon: vms
},
{
name: 'Apple Store',
time: '13:43',
price: 322,
icon: apple
}
]
},
{
date: 'September 8, 2012',
total: 754,
purchases: [
{
name: 'Virgin Megastores',
time: '12:24',
price: 432,
icon: vms
},
{
name: 'Apple Store',
time: '13:43',
price: 322,
icon: apple
}
]
},
]
You problem lies with the way you filter your data.
newData = content.filter(function (item) {
item.purchases.filter(function (i) {
const itemData = i.name.toUpperCase();
const textData = searchText.toUpperCase();
return itemData.includes(textData);
});
});
The filter
function expects a callback function that returns a boolean to determine whether an item should be included or not. Because your contect.filter
call doesn't return anything from its callback the final newData
is empty.
So let's try to adjust the code into something working
newData = content.filter(function (item) {
// check if any purchase has matches; and keep the filtered results
const filteredPurchases = item.purchases.filter(function (i) {
const itemData = i.name.toUpperCase();
const textData = searchText.toUpperCase();
return itemData.includes(textData);
});
// now let the parent know if it should include this item in the filter
// if the length is higher than zero, filter will include this item
return filteredPurchases.length;
});
In your comment you say that you only want to show the applicable purchases. Let's adjust the code a little bit more. We will map
the content to only include applicable purchases and then filter
on all items with applicable purchases
newData = content.map(function (item) {
// check if any purchase has matches; and keep the filtered results
const filteredPurchases = item.purchases.filter(function (i) {
const itemData = i.name.toUpperCase();
const textData = searchText.toUpperCase();
return itemData.includes(textData);
});
// now return a newly composed item with only applicable purchases
return {
...item,
purchases: filteredPurchases
};
}).filter(function (item) {
// now only keep items with applicable purchases.
return item.purchases.length
});