Reputation: 1673
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
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
Reputation: 413
You need to make the following changes in the code to work .
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
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