i'm trying to build a filter/search buttons using pure JavaScript. the idea is simple at least in my mind , you click a type and all the other types will be set to (hide) will the ones you want remain .
the javascript code is as follows
const btns = document.querySelectorAll('.btn');
const storeProducts = document.querySelectorAll('.article-card');
for (i = 0; i < btns.length; i ) {
btns[i].addEventListener('click', (e) => {
e.preventDefault()
const filter = e.target.dataset.filter;
console.log(filter);
console.table(storeProducts);
storeProducts.forEach((product)=> {
if (filter === 'all'){
product.style.display = 'block'
} else {
if (product.classList.contains(filter)){
product.style.display = 'block'
} else {
product.style.display = 'none'
}
}
});
});
};
the HTML content is coming from mysql database , and it gets looped to print the element the element is as follows
print '
<article style="display:block;" >
<div >
<a href="#" >' . $row['special'] . '</a>
<h3 >' . $row['name'] . '</h3>
<p >some notes here</p>
<div >
</article> ';
the filter buttons
<div >
<a href="#" data-filter="all">All</a>
<a href="#" data-filter="type1">type1</a>
<a href="#" data-filter="type2">type2</a>
<a href="#" data-filter="type3">type3</a>
<a href="#" data-filter="type4">type4</a>
</div>
the buttons i press do absolutely nothing except for the values to show in the console , also i would like to point out this console.table shows nothing
console.table(storeProducts);
EDIT : problem solved !!! actually the script was OK but the browser was just running a cached version of the script , so it didn't work as intended but after clearing the cache now it works perfectly .
CodePudding user response:
without seeing your code and how data is being populated, I can not be too sure, but are you including the script before fetching the database (in the html file). It'll be much more helpful if you could provide us with a sample populated html file.
CodePudding user response:
I suspect the error is at this point. You check if the filter word is contained in the ClassList. But you get the filter word from the data attribute data-filter
. So I guess you have to look there as well.
if (product.dataset.filter.contains(filter)){
In my example i generate the products by javascript. I saw you generate serverside. But it doesn't really matter here because the function works for both.
working exammple
let products = {
data: [
{
productName: "Regular White T-Shirt",
category: "Topwear",
price: "30",
image: "https://via.placeholder.com/400",
},
{
productName: "Beige Short Skirt",
category: "Bottomwear",
price: "49",
image: "https://via.placeholder.com/400",
},
{
productName: "Sporty SmartWatch",
category: "Watch",
price: "99",
image: "https://via.placeholder.com/400",
},
{
productName: "Basic Knitted Top",
category: "Topwear",
price: "29",
image: "https://via.placeholder.com/400",
},
{
productName: "Black Leather Jacket",
category: "Jacket",
price: "129",
image: "https://via.placeholder.com/400",
},
{
productName: "Stylish Pink Trousers",
category: "Bottomwear",
price: "89",
image: "https://via.placeholder.com/400",
},
{
productName: "Brown Men's Jacket",
category: "Jacket",
price: "189",
image: "https://via.placeholder.com/400",
},
{
productName: "Comfy Gray Pants",
category: "Bottomwear",
price: "49",
image: "https://via.placeholder.com/400",
},
],
};
for (let i of products.data) {
//Create Card
let card = document.createElement("div");
//Card should have category and should stay hidden initially
card.classList.add("card", i.category, "hide");
//image div
let imgContainer = document.createElement("div");
imgContainer.classList.add("image-container");
// dataSet
let dataSet = card.setAttribute('data-filter', i.category);
//img tag
let image = document.createElement("img");
image.setAttribute("src", i.image);
imgContainer.appendChild(image);
card.appendChild(imgContainer);
//container
let container = document.createElement("div");
container.classList.add("container");
//product name
let name = document.createElement("h5");
name.classList.add("product-name");
name.innerText = i.productName.toUpperCase();
container.appendChild(name);
//price
let price = document.createElement("h6");
price.innerText = "$" i.price;
container.appendChild(price);
card.appendChild(container);
document.getElementById("products").appendChild(card);
}
//parameter passed from button (Parameter same as category)
function filterProduct(value) {
//Button class code
let buttons = document.querySelectorAll(".button-value");
buttons.forEach((button) => {
//check if value equals innerText
if (value.toUpperCase() == button.innerText.toUpperCase()) {
button.classList.add("active");
} else {
button.classList.remove("active");
}
});
//select all cards
let elements = document.querySelectorAll(".card");
//loop through all cards
elements.forEach((element) => {
//display all cards on 'all' button click
if (value == "all") {
// element.classList.remove("hide");
element.classList.remove("hide");
} else {
//Check if element contains category class
if (element.getAttribute('data-filter') == value) {
//display element based on category
element.classList.remove("hide");
} else {
//hide other elements
element.classList.add("hide");
}
}
});
}
//Initially display all products
window.onload = () => {
filterProduct("all");
};
* {
padding: 0;
margin: 0;
box-sizing: border-box;
border: none;
outline: none;
font-family: "Poppins", sans-serif;
}
body {
background-color: #f5f8ff;
}
.wrapper {
width: 95%;
margin: 0 auto;
}
#buttons {
margin-top: 30px;
text-align: center;
}
.button-value {
border: 2px solid #6759ff;
padding: 1em 2.2em;
border-radius: 3em;
background-color: transparent;
color: #6759ff;
cursor: pointer;
}
.active {
background-color: #6759ff;
color: #ffffff;
}
#products {
display: grid;
grid-template-columns: auto auto auto;
grid-column-gap: 1.5em;
padding: 2em 0;
}
.card {
background-color: #ffffff;
max-width: 18em;
margin-top: 1em;
padding: 1em;
border-radius: 5px;
box-shadow: 1em 2em 2.5em rgba(1, 2, 68, 0.08);
}
.image-container {
text-align: center;
}
img {
max-width: 100%;
object-fit: contain;
height: 15em;
}
.container {
padding-top: 1em;
color: #110f29;
}
.container h5 {
font-weight: 500;
}
.hide {
display: none;
}
@media screen and (max-width: 720px) {
img {
max-width: 100%;
object-fit: contain;
height: 10em;
}
.card {
max-width: 10em;
margin-top: 1em;
}
#products {
grid-template-columns: auto auto;
grid-column-gap: 1em;
}
}
<div >
<div id="buttons">
<button onclick="filterProduct('all')">All</button>
<button onclick="filterProduct('Topwear')">
Topwear
</button>
<button onclick="filterProduct('Bottomwear')">
Bottomwear
</button>
<button onclick="filterProduct('Jacket')">
Jacket
</button>
<button onclick="filterProduct('Watch')">
Watch
</button>
</div>
<div id="products"></div>
</div>
CodePudding user response:
Mind Using CSS? If yes I can make a solution for you.