Search code examples
react-nativereact-native-flatlistsearchbar

Searching through a flatlist returns no results


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
            }
        ]
    },
]

Solution

  • 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
    });