Creating a dynamic and interactive Flatlist component in React Native by implementing a search functionality

I want to create a searchable flatlist for skills using the JSON data provided below:

const employeeList = [
  {
    id: "1",
    name: "John",
    image: require("../images/John.png"),
    skills: [
      { id: 1, name: "Cooking" },
      { id: 2, name: "Climbing" },
    ],
  },
  {
    id: "2",
    name: "Pat",
    image: require("../images/Pat.png"),
    skills: [
      { id: 1, name: "Cooking" },
      { id: 2, name: "Rowing" },
    ],
  },
];

export default employeeList;

I have managed to display all employees and their skills but my search feature currently filters only by employee names. I would like to enhance it to search for skills as well and show the employee associated with that skill.

// Search Bar Filter Functionality in React Native FlatList
// Source: https://aboutreact.com/react-native-search-bar-filter-on-listview/

// Import necessary components
import React, { useState, useEffect } from "react";
import {
  SafeAreaView,
  Text,
  StyleSheet,
  View,
  FlatList,
  TextInput,
  Image,
  TouchableOpacity,
} from "react-native";

// Import the employee JSON data
import employeeList from "../json/employee";

const AllListScreen = ({ navigation, route }) => {
  const [search, setSearch] = useState("");
  const [filteredDataSource, setFilteredDataSource] = useState([]);
  const [masterDataSource, setMasterDataSource] = useState([]);

  // Populate the initial data sources with employee list
  useEffect(() => {
    setFilteredDataSource(employeeList);
    setMasterDataSource(employeeList);
    console.log(JSON.stringify(employeeList[0].skills)); // Display skills
  }, []);

  // Function to filter based on search text
  const searchFilterFunction = (text) => {
    if (text) {
      const newData = masterDataSource.filter(function (item) {
        const itemData = item.name ? item.name.toUpperCase() : "".toUpperCase();
        const textData = text.toUpperCase();
        return itemData.indexOf(textData) > -1;
      });
      setFilteredDataSource(newData);
      setSearch(text);
    } else {
      setFilteredDataSource(masterDataSource);
      setSearch(text);
    }
  };

  // Component to render each item in the FlatList
  const ItemView = ({ item, index }) => {
    return (
      <View>
        {item.skills.map((v, i) => (
          <>
            <TouchableOpacity
              onPress={() => console.log(v.name)}
              style={styles.itemStyle}
              key={item.id}
            >
              <Image
                source={{ uri: "https://source.unsplash.com/random" }}
                style={{ height: 50, width: 50 }}
              />
              <View style={styles.textPortion}>
                <Text>{item.name}</Text>
                <Text>{v.name.toUpperCase()}</Text>
              </View>
            </TouchableOpacity>
            <ItemSeparatorView />
          </>
        ))}
      </View>
    );
  };

  // Component to render separator between items
  const ItemSeparatorView = () => {
    return (
      <View
        style={{
          height: 0.5,
          width: "100%",
          backgroundColor: "#C8C8C8",
        }}
      />
    );
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View style={styles.container}>
        <TextInput
          style={styles.textInputStyle}
          onChangeText={(text) => searchFilterFunction(text)}
          value={search}
          underlineColorAndroid="transparent"
          placeholder="Search Here"
        />
        <FlatList
          data={filteredDataSource}
          keyExtractor={(item, index) => index.toString()}
          renderItem={ItemView}
        />
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: "#FFFFFF",
  },
  itemStyle: {
    flex: 1,
    padding: 8,
    flexDirection: "row",
  },
  textInputStyle: {
    height: 50,
    borderWidth: 1,
    paddingLeft: 20,
    margin: 6,
    borderColor: "#009688",
    backgroundColor: "#FFFFFF",
    borderRadius: 5,
  },
  textPortion: {
    flexWrap: "wrap",
    flexShrink: 1,
    marginLeft: 6,
  },
});

export default AllListScreen;

You can view the current display of the app here. Any assistance on improving the search functionality for skills is greatly appreciated. Thank you.

Answer №1

After some restructuring of the JSON data into an array format, I managed to successfully implement the desired functionality:

skillData = [];

for (let category in employeeInfo) {
  if (employeeInfo.hasOwnProperty(category)) {
    for (let skillItem in employeeInfo[category].skills) {
      skillData.push({
        name: employeeInfo[category].name,
        skill: employeeInfo[category].skills[skillItem].name,
      });
    }
  }
}

I then made a modification to my search filter to focus on filtering by skill rather than name:

 // utilizing employee data as the source for filtering
  useEffect(() => {
    setFilteredResults(skillData);
    setMasterResults(skillData);
    console.log(JSON.stringify(employeeInfo[0].skills));
  }, []);

  
  const applySearchFilter = (text) => {
    if (text) {
      const filteredData = masterResults.filter(function (entry) {
        const searchData = entry.skill ? entry.skill.toUpperCase() : "".toUpperCase();
        const searchText = text.toUpperCase();
        return searchData.indexOf(searchText) > -1;
      });
      setFilteredResults(filteredData);
      setSearchQuery(text);
    } else {
      setFilteredResults(masterResults);
      setSearchQuery(text);
    }
  };

And here is the modified ItemView component:

  const DisplaySkills = ({ item }) => {
    return (
        <View style={styles.itemDesign}>
          <Image
            source={{ uri: "https://source.unsplash.com/random" }}
            style={{ height: 50, width: 50 }}
          />
          <Text style={styles.textContent}>
            {item.name.toUpperCase()}
            {"\n"}
            {item.skill.toUpperCase()}
          </Text>
        </View>
    );
  };

While there may be other ways to achieve this functionality, I hope sharing this approach can benefit someone.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging the power of promises to handle multiple requests

Recently, I encountered an issue while trying to use the request-promise module to check multiple websites simultaneously. When using Promise.all as intended, the promise would return with the first rejection. I sought a better way to execute multiple requ ...

Having difficulty assigning a value to a specific element within an array

When a button labeled "update" is clicked in an array called admin, I would like to display a div. The goal is for the div to appear below the selected element only and not affect any others in the array. function Admin(props) { const [showMe, setShowMe ...

The Facebook login pop-up is not visible, however, it is still delivering on its promise

I am currently utilizing the Angular Facebook service found at this link. Within my controller, I am attempting to invoke the method $facebook.login() when a button is clicked using ng-click. Although the promise is returned and the code inside is execute ...

Efficient url routing in a client-side React application powered by Express server

Currently, I am utilizing Express to load a single-page client-side app in React.js with react-router. The structure involves having /about and /contact as standard jade views, while /ui serves as the actual React app. Any further navigation beyond /ui, su ...

Populate the ng-model attribute dynamically based on the data in a JSON

Here is a JSON example that I have: fields: [ { name: "my_field_name", type: "text", placeholder: "place holder text" }], I aim to dynamically generate form controls based on the field type and assign them an ...

Executing an AJAX POST request from one domain (localhost:9393) to another domain (localhost:9696) using Spring Rest

I am encountering an issue with a form on one app running on localhost:9393. The JavaScript function used to post data is: function registerClient() { var postData = $("#client-reg").serializeArray(); var formURL = "http://localhost:9393/mPaws/client/re ...

React JS is not allowing me to enter any text into the input fields despite my attempts to remove the value props

Currently, I am working on creating a Contact Form using React Js. I have utilized react bootstrap to build the component, but unfortunately, when attempting to type in the input fields, the text does not change at all. import React, {useState} from ' ...

Learn how to incorporate SAX parser into an Angular 2 project by utilizing TypeScript

Encountering challenges while trying to integrate the sax parser [parser.ts] into my project. import sax = require("sax"); export class MyParser { //my parser code } When attempting to utilize it [app.component.ts]: import {MyParser} from './pa ...

Tips for aligning ticks to the left on a d3 bar chart

i recently finished creating a stacked bar graph with varying tick lengths on the y-axis side. my goal is to align the text within the ticks to the left, similar to this example: http://jsfiddle.net/2khbceut/2/ here is the HTML: <title>Diverging Sta ...

Display the final value of an Android Viewpager based on the array size

Having trouble displaying all the values in my json array using viewpager in my Android app. Can someone please review my code and provide a solution? Thanks! package com.example.vasundharaapp; import java.util.ArrayList; import java.util.List; import ...

What is the best way to assign the value of an HTTP GET request to a subarray in Angular 8

Attempting to store data in a sub-array (nested array) but despite receiving good response data, the values are not being pushed into the subarray. Instead, an empty array is returned. for (var j=0;j<this.imagesdataarray.length;j++){ this.http.g ...

What could be causing a Typescript-defined class property to unexpectedly appear as undefined?

My component has a property called options, which I have defined in the class. However, when I run the code in the browser, it's showing up as undefined. Despite thoroughly checking the code logic, I can't seem to pinpoint any issues. This could ...

Canvas in the off state has been removed

My goal is to create a basic JavaScript library that includes rotating, translating, and scaling the canvas. One issue I am facing is when I rotate the canvas, half of the content ends up getting deleted because the center of rotation is set at (0, 0). I ...

Converting XML data from Oracle to JSON format in Postgres

I need assistance with migrating Oracle code to PostgreSQL. In Oracle, we use XML while in PostgreSQL we use JSON. I am facing challenges with some basic aspects during the migration process, For instance, in Oracle, We have a function called newDOMDocum ...

Exploring the world of Javascript: The significance of variable scope and its

Encountered a unique challenge while attempting to execute an ajax call and confine the function's actions to itself. Below is the code snippet: $(document).on('click', 'input.action', function(event) { var self = this; ...

Tips to enhance web page loading speed when parsing JSON data from a URL

While extracting data from a JSON file accessed via URL, I am experiencing long loading times. Surprisingly, the website manages to display the same data only when it's ready, and I aspire to achieve a similar functionality. I have yet to discover a ...

Angular function triggered by clicking that takes two parameters

Is there a way to pass two arguments in this method? <tr *ngFor="let match of item.matches " (click)="openMatchContent(match,$event)" openMatchContent(match: any,event:any) {} When I try to run this code, I receive an error statin ...

Injecting HTML into Vue component

Currently, I am passing some parameters into a Vue component <Slider :images= "['/img/work/slide2.png', '/img/work/slide2.png', '/img/work/slide3.png']" :html="['<div>hello</div>', ' ...

What should I do if one of my images fails to load after the previous one has loaded successfully?

My code is designed to create an animation using 3 canvases: one for the base image, one for the streamline wind map drawing, and another for an image covering part of the drawing. The following code displays the uploading of two images. var im ...

Looking for assistance in setting a new initial state for a javascript toggle on page load

Need assistance with customizing the Youtube-TV JS plugin for a client website? The current setup loads the player with a playlist in an open state, but the requirement is to load it with the toggle closed, displaying the array of playlists instead. If y ...