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.
Your solution isn't working because of a couple of issues:
forEach
. data
is a single card element. Looping through it will loop through it's properties, which is not what you need..product-name
class, not the .produce-name
. Also be sure to use querySelector
instead of querySelectorAll
if 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.