I have some JSON (see end) that contains two values. I need the search to filter based on either value. I documented every part of the search/display of code
Here is my useState variables:
const [dataBackup, setdataBackup] = useState([]) const [dataSource, setdataSource] = useState([])
Here is my FlatList:
<SectionList
contentContainerStyle={{ paddingHorizontal: 10}}
stickySectionHeadersEnabled={false}
sections={dataSource}
keyExtractor={(item, index) => {
return index.toString();
}}
renderSectionHeader={({ section }) => (
<>
<Text style={styles.sectionHeader}>{section.title}</Text>
{section.data ? (
<OptimizedFlatList
horizontal
data={section.data}
keyExtractor={(item, index) => {
return index.toString();
}}
renderItem={({ item }) => <ListItem item={item} navigation={navigation} />}
showsHorizontalScrollIndicator={false}
/>
) : null}
</>
)}
renderItem={({ item, section, navigation }) => {
if (section.data) {
return null;
}
return <ListItem item={item} navigation={navigation}/>;
}}
/>
Here is the NOT WORKING filtering logic:
filterList = (text) => {
for (let i = 0; i < dataBackup.length; i ) {
const t = dataBackup[i];
newData = t["data"].filter((item) => {
const itemData = item["name"].toLowerCase();
const textData = text.toLowerCase();
setdataSource(itemData.indexOf(textData) > -1)
});
}
}
Here is what the data looks like:
[{
title: 'Leg',
data:[
{
"bodyPart": "lower legs",
"equipment": "assisted",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/1708.gif",
"id": "1708",
"name": "assisted lying calves stretch",
"target": "calves",
"broad_target": "legs",
"ppl": "legs"
},
{
"bodyPart": "lower legs",
"equipment": "smith machine",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/1396.gif",
"id": "1396",
"name": "smith toe raise",
"target": "calves",
"broad_target": "legs",
"ppl": "legs"
}
]
},
{
title: 'Back',
data:[
{
"bodyPart": "Back",
"equipment": "assisted",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/1708.gif",
"id": "1708",
"name": "Back1",
"target": "Back",
"broad_target": "Back",
"ppl": "Pull"
},
{
"bodyPart": "Back",
"equipment": "smith machine",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/1396.gif",
"id": "1396",
"name": "Back2",
"target": "Back",
"broad_target": "Back",
"ppl": "Pull"
}
]
}]
I want it to filter by Title OR by name
CodePudding user response:
So i do not see a title field on your data object. But this is how you can do it for finding exact match. The implementation is for filtering on name and equipment. If you need a partial match you can do item.name.toLowerCase().split(/\s |./).includes(query.toLowerCase())
const dataSample = [
{ "title": "red",
"data": [{
"bodyPart": "back",
"broad_target": "back",
"equipment": "cable",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/0007.gif",
"id": 1,
"name": "alternate item",
"ppl": "pull",
"target": "lats",
"thumbnail": "https://images.unsplash.com/photo-1640334554717-a7a4ce5d0045?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=296&q=20"
}
]
},
{ "title": "blue",
"data": [{
"bodyPart": "back",
"broad_target": "back",
"equipment": "cable",
"gifUrl": "http://d205bpvrqc9yn1.cloudfront.net/0007.gif",
"id": 1,
"name": "alternate",
"ppl": "pull",
"target": "lats",
"thumbnail": "https://images.unsplash.com/photo-1640334554717-a7a4ce5d0045?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=296&q=20"
}
]
}
]
const filterData = (data = [], query) =>
data.filter(item => item.title.toLowerCase() === query.toLowerCase()
||
item.data.find(element => element.name.toLowerCase() === query.toLowerCase())
)
console.log(filterData(dataSample, 'alternate'))
console.log(filterData(dataSample, 'red'))
Try this out, updated as per your comment:
const filterData = (data = [], query) =>
data.filter(item => item.title.toLowerCase().includes(query.toLowerCase())
||
item.data.find(element => element.name.toLowerCase().includes(query.toLowerCase()))
)
<SearchBar
onChangeText={(text) =>
text.length !== 0 ?
setdataSource(filterData(dataBackup, text)):
setdataSource(dataBackup)}
onClearPress={() => setdataSource(dataSource)}
/>
When i gave it another thought, this is the perfect solution for your case covering all other scenarios.
useEffect(() => {
console.log("search key", searchKey)
if(searchKey.length != 0){
setdataSource(filterData(dataBackup, searchKey))
} else{
setdataSource(dataBackup)
}
}, [searchKey])
const filterData = (data = [], query) => {
const foundItems = searchForItem(data, query)
const foundDataItems = searchForDataInItem(data, query)
const uniqueItemTitles = [...new Set([...Object.keys(foundItems),...Object.keys(foundDataItems)])];
return uniqueItemTitles.reduce((title, accumulator) => {
const itemHadTitleMatchedToQuery = foundItems.find(element => element.title === title)
const itemHadDataMatchedToQuery = foundDataItems.find(element => element.title === title)
if(itemHadTitleMatchedToQuery) {
accumulator.push({
...itemHadTitleMatchedToQuery
})
} else {
accumulator.push({
...itemHadDataMatchedToQuery
})
}
return accumulator;
}, []);
}
const searchForItem = (data = [], query) => {
const result = data.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
)
return result
}
const searchForDataInItem = (data = [], query) => {
return data.map(item => {
return { ...item, data: item.data.filter(element => element.name.toLowerCase().includes(query.toLowerCase()))}
}).filter(item => item.data.length != 0)
}
CodePudding user response:
After working with @Dheeraj Sharma, we came up with:
useEffect(() => {
console.log("search key", searchKey)
if(searchKey.length != 0){
setdataSource(filterData(dataBackup, searchKey))
} else{
setdataSource(dataBackup)
}
}, [searchKey])
const filterData = (data = [], query) => {
const foundItems = searchForItem(data, query)
const foundData = searchForDataInItem(data, query)
if(foundItems.length !== 0){
return foundItems;
}
return foundData
}
const searchForItem = (data = [], query) => {
const result = data.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
)
return result
}
const searchForDataInItem = (data = [], query) => {
return data.map(item => {
return { ...item, data: item.data.filter(element => element.name.toLowerCase().includes(query.toLowerCase()))}
}).filter(item => item.data.length != 0)
}