Trying to filter user input so when user starts to type run function.
What I want
When the user starts to type, start looking for cards when the class product-name and display block results.
ex:
user starts typing something…
Piz
display block card Pizza
My Javascript
// search bar function
const search = () => {
var input, filter, data, productName, i, txtValue;
data = this.data;
input = document.getElementById("user-input");
filter = input.value.toUpperCase();
getInput = input.value;
console.log("User input: " + getInput);
document.querySelectorAll('.cards').forEach(function(data) {
for (i = 0; i < data.length; i++) {
productName = data[i].querySelectorAll(".produce-name")[0];
txtValue = productName.textContent || productName.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
data[i].style.display = "";
} else {
data[i].style.display = "none";
}
}
});
};
My HTML
<form class="form-inline flexSearchWrapper">
<input class="form-control mr-sm-2" type="search" placeholder="Busca algo..." aria-label="Search" id="user-input" onkeyup="search();">
</form>
I can’t figure out what I’m doing wrong? At the moment my console.log() output just gets the user input and what they are currently typing.Thanks!
UPDATE
Card Info HTML
<div class="card cards">
<img src="https://images.vexels.com/media/users/3/185266/isolated/lists/815ded7afc1c54dfb5a60f81f68f928b-pizza-slice-icon.png" class="card-img-top p-3 product-image" alt="...">
<div class="card-body">
<h5 class="card-title product-name">Pizza</h5>
<h5 class="text-muted fw-bold card-price product-price">S/ 12.50 PEN</h5>
</div>
</div>
I put it in a .forEach loop in order to get the .product-name of each card.
>Solution :
Your solution isn’t working because of a couple of issues:
- You have a nested loop inside of
forEach.datais a single card element. Looping through it will loop through it’s properties, which is not what you need. - The product name is in the
.product-nameclass, not the.produce-name. Also be sure to usequerySelectorinstead ofquerySelectorAllif you need a single element.
Below I’ve written a different version of your code. Instead of looking up the title element of each card, add the data you need to the .card element itself. You can do this with data attributes. In this case I’ve added data-name to each card, which is going to be the value which we can filter on.
Then when you input something in the search field, get the value of the field and loop over all the cards. If the data-name value contains anything that you’ve entered, then a class will be added or removed to show or hide the card. By using classes you can keep CSS in charge of the styles.
const form = document.querySelector('#search');
const cards = document.querySelectorAll('.card')
form.addEventListener('input', event => {
const value = event.target.value.trim().toLowerCase();
for (const card of cards) {
const { name } = card.dataset;
const shouldShow = name.includes(value);
card.classList.toggle('hide', !shouldShow);
}
});
.cards {
display: flex;
gap: 10px;
}
.card.hide {
display: none;
}
<form id="search" class="form-inline flexSearchWrapper">
<input class="form-control mr-sm-2" type="search" placeholder="Busca algo..." aria-label="Search" id="user-input">
</form>
<div class="cards">
<div class="card" data-name="pizza">
<img src="https://images.vexels.com/media/users/3/185266/isolated/lists/815ded7afc1c54dfb5a60f81f68f928b-pizza-slice-icon.png" class="card-img-top p-3 product-image" alt="...">
<div class="card-body">
<h5 class="card-title product-name"><a href="#" class="test">Pizza</h5>
<p class="text-muted fw-bold card-price product-price">S/ 12.50 PEN</p>
</div>
</div>
<div class="card" data-name="penne">
<img src="https://images.vexels.com/media/users/3/185266/isolated/lists/815ded7afc1c54dfb5a60f81f68f928b-pizza-slice-icon.png" class="card-img-top p-3 product-image" alt="...">
<div class="card-body">
<h5 class="card-title product-name"><a href="#" class="test">Penne</h5>
<p class="text-muted fw-bold card-price product-price">S/ 12.50 PEN</p>
</div>
</div>
</div>
I’ve also used the cards class differently as it doesn’t make sense – at least for me – for a single card to have both card and cards as a class.
And be sure to use your headings h1...h6 properly. It’s not for styling but to explain to the browser how it should interpret the content.