SUMguy
SUMguy

Reputation: 1673

Search Filter in React/JS

I'm using React to map through a series of data to be displayed in cards on a page. What I'm trying to do is implement search/filter functionality so that when the user types in "bicep", they only see the cards that contain the word "bicep". Ideally I would like to search the entire card, including the description. No matter what I try, I can't get the search bar to have any effect on the cards. I don't get any error messages, but when I search for anything, none of the cards are filtered out, even if they don't contain the search term.

Here is the CodeSandbox link. The search function I'm attempting to use is below:

function mySearchFunction() {
  var input, filter, div, dl, a, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  div = document.getElementById("myDiv");
  dl = div.getElementsByTagName("dl");
  for (i = 0; i < dl.length; i++) {
    a = dl[i].getElementsByTagName("span")[1];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      dl[i].style.display = "";
    } else {
      dl[i].style.display = "none";
    }
  }
}

I'm fairly new to Javascript so if there is another function/feature that you would recommend, I'm probably just not aware of it yet, and I'm open to anything, as long as it uses hooks instead of classes, and keep in mind I'm still learning this so I'm trying to take things one step at a time (i.e. I don't know anything about Angular or Vue or other non-React front-end frameworks).

Upvotes: 1

Views: 1707

Answers (3)

Jon
Jon

Reputation: 158

import React, {useState} from "react";
import Entry from "./Entry";
import emojipedia from "../emojipedia";

function App() {
  const [results, setResults] = useState([])

  function mySearchFunction(value) {
    const results = emojipedia.filter(emoji => emoji.name.replace(/ /g,'').toLowerCase().includes(value.toLowerCase()))
    setResults(results)
  }

  return (
    <div>
      <h1>
        <span>emojipedia</span>
      </h1>

      <input
        type="text"
        id="myInput"
        onChange={e => mySearchFunction(e.target.value)}
        placeholder="Search for names.."
      />

      <div id="myDiv">
        <dl className="dictionary">
        {
          results.length === 0 ? 'no results' : results.map(result => {
            return <Entry key={result.id}
                          emoji={result.emoji}
                          name={result.name}
                          description={result.meaning} />
                        })
          }
          </dl>
      </div>
    </div>
  );
}

export default App;

Upvotes: 0

pallavi richhariya
pallavi richhariya

Reputation: 413

You need to make the following changes in the code to work .

  1. You need to add the state in the component and make use of useState .
  2. I added the onChange eventHandler to handle the input change.
  3. Rewritten the filter method to filter the data based on the name property. You can make it generic by passing the property on what you want to filter the data.
  4. Binded the state variable emojis , in the JSX , so that it re-renders the component when you change the state.

Here is the working solution: https://codesandbox.io/s/emoji-site-nc81j?file=/src/components/App.jsx

See the code below

function App() {
  const [emojis, setEmojis] = useState(emojipedia);

  function mySearchFunction(event) {
    var tempData = emojipedia.slice();
    tempData = tempData.filter(
      data => data.name.indexOf(event.target.value) > -1
    );
    setEmojis(tempData);
  }

  function createEntry(emojiTerm) {
    return (
      <Entry
        key={emojiTerm.id}
        emoji={emojiTerm.emoji}
        name={emojiTerm.name}
        description={emojiTerm.meaning}
      />
    );
  }

  return (
    <div>
      <h1>
        <span>emojipedia</span>
      </h1>

      <input
        type="text"
        id="myInput"
        onChange={mySearchFunction}
        placeholder="Search for names.."
      />

      <div id="myDiv">
        <dl className="dictionary">{emojis.map(createEntry)}</dl>
      </div>
    </div>
  );
}

export default App;

Upvotes: 0

Ashwel
Ashwel

Reputation: 1240

You can achive that this way for example:

Attach onChange handler on input which set stateHook filter, after every change of state render method is called.

Emojies are rendered with filter(u must handle Case Insensitive Search here etc..) and they are mapped to ur object.

Here is code on CodeSandbox

function App() {
  const [filter, setFilter] = useState("");

  return (
    <div>
      <h1>
        <span>emojipedia</span>
      </h1>

      <input
        type="text"
        id="myInput"
        onChange={e => setFilter(e.target.value)}
        placeholder="Search for names.."
      />

      <div id="myDiv">
        <dl className="dictionary">
          {emojipedia
            .filter(emoji => {
              return (
                emoji.name.includes(filter) || emoji.meaning.includes(filter)
              );
            })
            .map(createEntry)}
        </dl>
      </div>
    </div>
  );
}

Upvotes: 2

Related Questions