product cardsI need a help of solving my below issues:
I have generated dynamically cards with javascript and try to get the id when product is clicked.The results what i Have done are:
1)when click the first product it gets the wrong id,showing the details of the last product 2)the event listener works only for the first element so i can't show the other product.
product-list.js
let cardData = [
{
id: 1,
imgFile: 'images/products/marievi5.jpg',
heading: 'Marievi the Influencer',
body: 'this is card body',
price: 150,
},
{
id: 2,
imgFile: 'images/products/rock1.jpg',
heading: 'card 2',
body: 'this is card body',
price: 200,
},
{
id: 3,
imgFile: 'images/products/marievi5.jpg',
heading: 'card 3',
body: 'this is card body',
price: 400,
},
{
id: 4,
imgFile: 'images/products/marievi5.jpg',
heading: 'card 4',
body: 'this is card body',
price: 300,
},
];
const createCard = () => {
let cardContainer = document.querySelector('.card-container');
cardContainer.innerHTML = ''; // Clear the grid first
cardData.forEach((data) => {
//create product card
let card = document.createElement('div');
card.classList.add('card-body');
card.setAttribute('data-product-id', data.id);
// Add content inside the product card
let content = `<div class="card-container py-5">
<div class="row ">
<div class="col">
<div class="listProduct">
<div class="card-body product-card" data-product-id="${data.id}">
<img class="card-img-top " id="productImg" src="${data.imgFile}" alt="Card image cap">
<div class=" product-details" id="details-${data.id}">
<h5 class="card-title mb-3 fw-bold ">${data.heading}</h5>
<p class="card-text text-muted mb-4">${data.body}</p>
<div class="d-flex justify-content-between align-items-center">
<span class="product-price">Price:${data.price}</span>
</div>
<button class="btn btn-custom text-white px-4 py-2 rounded-pill" data-product-id="${data.id}"btn btn-primary">View Details</button>
</div>
</div>
</div>
</div>
</div>
</div>`;
cardContainer.innerHTML += content;
document.querySelector('.listProduct').addEventListener('click',function(){
let productId = data.id; // This should not be undefined
console.log(productId);
window.location.href = `ProductDetails1.html?id=${productId}`;
});
return card;
})
}
// Call the function to generate products on page load
createCard(cardData);
ProductDetails.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Product Details</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=1.0">
<meta charset="utf-8">
<link href="/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script src=".js" crossorigin="anonymous"></script>
<script src="//code.jquery/jquery.min.js"></script>
<link rel="stylesheet" href="mystyle.css">
<link rel="stylesheet" href="ProductDetails.css">
</head>
<body>
<!--Navigation bar-->
<div id="nav-placeholder">
</div>
<script>
$(function () {
$("#nav-placeholder").load("nav.html");
});
</script>
<div class="container my-5 pt-5">
<div class=" row mt-5">
<div class="col-sm-8 d-flex flex-column d-inline-flex p-2 bd-highlight justify-content-around ">
<div class="detail">
<figure class="ProductItem-gallery">
<div class="image1">
<img src="" alt="">
</div>
</figure>
<div class="col">
<div class="content">
<h1 class="name"></h1>
<p class="price"></p>
<p class="description"></p>
<button class="btn btn-primary">Add to Cart</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let products = null;
fetch('./products.json')
.then(response => response.json())
.then(data => {
products = data;
showDetail();
})
//find this product
function showDetail() {
let detail = document.querySelector('.detail');
let productId = new URLSearchParams(window.location.search).get('id');
console.log("product id "+productId);
let thisProduct = products.filter(value => {
return value.id == productId
})[0];
//if there is no product has id =productId
//=>return to home page
if (!thisProduct) {
window.location.href = "/shoplist.html";
}
//and if has,add data this product in html
detail.querySelector('.image1 img').src = thisProduct.imgFile;
detail.querySelector('.name').innerText = thisProduct.heading;
detail.querySelector('.price').innerText = '$' + thisProduct.price;
detail.querySelector('.description').innerText = thisProduct.body;
}
</script>
</body>
</html>
shoplist.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>ShopList</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=1.0">
<meta charset="utf-8">
<link href="/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script src=".js" crossorigin="anonymous"></script>
<!-- <script src=".10.2.js"></script> -->
<link rel="stylesheet" href="shopstyle.css">
<link rel="stylesheet" href="mystyle.css">
<script src="//code.jquery/jquery.min.js"></script>
</head>
<body>
<!--Navigation bar-->
<div id="nav-placeholder">
</div>
<script>
$(function () {
$("#nav-placeholder").load("nav.html");
});
</script>
<h1 class="heading-top-op text-center">Original Paintings</h1>
<div class="card-container">
<div class="listProduct"></div>
</div>
<script src="product-list.js" defer>
</script>
<script>
let products = null;
fetch('./products.json')
.then(response => response.json())
.then(data => {
products = data;
console.log(products);
addDataToHTML();
})
let listProduct = document.querySelector('.listProduct');
function addDataToHTML() {
products.forEach(product => {
//create new element item
let newProduct = document.createElement('a');
newProduct.setAttribute("id", "clicktag");
newProduct.href = '/ProductDetails1.html?id=' + product.id;
newProduct.classList.add('item');
newProduct.innerHTML = `
<img src="${product.imgFile}"/>;
<h2>${product.heading}</h2>;
<p class="price">${product.price}</p>`;
//add this element in listProduct class
listProduct.appendChild(newProduct);
})
// end - of for
}
// end of fuction addDataToHtML
</script>
</body>
<!--footer -->
<div id="footer-placeholder">
</div>
<script>
$(function () {
$("#footer-placeholder").load("footer.html");
});
</script>
</html>
product cardsI need a help of solving my below issues:
I have generated dynamically cards with javascript and try to get the id when product is clicked.The results what i Have done are:
1)when click the first product it gets the wrong id,showing the details of the last product 2)the event listener works only for the first element so i can't show the other product.
product-list.js
let cardData = [
{
id: 1,
imgFile: 'images/products/marievi5.jpg',
heading: 'Marievi the Influencer',
body: 'this is card body',
price: 150,
},
{
id: 2,
imgFile: 'images/products/rock1.jpg',
heading: 'card 2',
body: 'this is card body',
price: 200,
},
{
id: 3,
imgFile: 'images/products/marievi5.jpg',
heading: 'card 3',
body: 'this is card body',
price: 400,
},
{
id: 4,
imgFile: 'images/products/marievi5.jpg',
heading: 'card 4',
body: 'this is card body',
price: 300,
},
];
const createCard = () => {
let cardContainer = document.querySelector('.card-container');
cardContainer.innerHTML = ''; // Clear the grid first
cardData.forEach((data) => {
//create product card
let card = document.createElement('div');
card.classList.add('card-body');
card.setAttribute('data-product-id', data.id);
// Add content inside the product card
let content = `<div class="card-container py-5">
<div class="row ">
<div class="col">
<div class="listProduct">
<div class="card-body product-card" data-product-id="${data.id}">
<img class="card-img-top " id="productImg" src="${data.imgFile}" alt="Card image cap">
<div class=" product-details" id="details-${data.id}">
<h5 class="card-title mb-3 fw-bold ">${data.heading}</h5>
<p class="card-text text-muted mb-4">${data.body}</p>
<div class="d-flex justify-content-between align-items-center">
<span class="product-price">Price:${data.price}</span>
</div>
<button class="btn btn-custom text-white px-4 py-2 rounded-pill" data-product-id="${data.id}"btn btn-primary">View Details</button>
</div>
</div>
</div>
</div>
</div>
</div>`;
cardContainer.innerHTML += content;
document.querySelector('.listProduct').addEventListener('click',function(){
let productId = data.id; // This should not be undefined
console.log(productId);
window.location.href = `ProductDetails1.html?id=${productId}`;
});
return card;
})
}
// Call the function to generate products on page load
createCard(cardData);
ProductDetails.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Product Details</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=1.0">
<meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/ce111f8d46.js" crossorigin="anonymous"></script>
<script src="//code.jquery.com/jquery.min.js"></script>
<link rel="stylesheet" href="mystyle.css">
<link rel="stylesheet" href="ProductDetails.css">
</head>
<body>
<!--Navigation bar-->
<div id="nav-placeholder">
</div>
<script>
$(function () {
$("#nav-placeholder").load("nav.html");
});
</script>
<div class="container my-5 pt-5">
<div class=" row mt-5">
<div class="col-sm-8 d-flex flex-column d-inline-flex p-2 bd-highlight justify-content-around ">
<div class="detail">
<figure class="ProductItem-gallery">
<div class="image1">
<img src="" alt="">
</div>
</figure>
<div class="col">
<div class="content">
<h1 class="name"></h1>
<p class="price"></p>
<p class="description"></p>
<button class="btn btn-primary">Add to Cart</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let products = null;
fetch('./products.json')
.then(response => response.json())
.then(data => {
products = data;
showDetail();
})
//find this product
function showDetail() {
let detail = document.querySelector('.detail');
let productId = new URLSearchParams(window.location.search).get('id');
console.log("product id "+productId);
let thisProduct = products.filter(value => {
return value.id == productId
})[0];
//if there is no product has id =productId
//=>return to home page
if (!thisProduct) {
window.location.href = "/shoplist.html";
}
//and if has,add data this product in html
detail.querySelector('.image1 img').src = thisProduct.imgFile;
detail.querySelector('.name').innerText = thisProduct.heading;
detail.querySelector('.price').innerText = '$' + thisProduct.price;
detail.querySelector('.description').innerText = thisProduct.body;
}
</script>
</body>
</html>
shoplist.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>ShopList</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=1.0">
<meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/ce111f8d46.js" crossorigin="anonymous"></script>
<!-- <script src="https://code.jquery.com/jquery-1.10.2.js"></script> -->
<link rel="stylesheet" href="shopstyle.css">
<link rel="stylesheet" href="mystyle.css">
<script src="//code.jquery.com/jquery.min.js"></script>
</head>
<body>
<!--Navigation bar-->
<div id="nav-placeholder">
</div>
<script>
$(function () {
$("#nav-placeholder").load("nav.html");
});
</script>
<h1 class="heading-top-op text-center">Original Paintings</h1>
<div class="card-container">
<div class="listProduct"></div>
</div>
<script src="product-list.js" defer>
</script>
<script>
let products = null;
fetch('./products.json')
.then(response => response.json())
.then(data => {
products = data;
console.log(products);
addDataToHTML();
})
let listProduct = document.querySelector('.listProduct');
function addDataToHTML() {
products.forEach(product => {
//create new element item
let newProduct = document.createElement('a');
newProduct.setAttribute("id", "clicktag");
newProduct.href = '/ProductDetails1.html?id=' + product.id;
newProduct.classList.add('item');
newProduct.innerHTML = `
<img src="${product.imgFile}"/>;
<h2>${product.heading}</h2>;
<p class="price">${product.price}</p>`;
//add this element in listProduct class
listProduct.appendChild(newProduct);
})
// end - of for
}
// end of fuction addDataToHtML
</script>
</body>
<!--footer -->
<div id="footer-placeholder">
</div>
<script>
$(function () {
$("#footer-placeholder").load("footer.html");
});
</script>
</html>
I recreated the requirement which is you asked, Hope this will work for you
Incorrect event binding :
document.querySelector('.listProduct')
, which only selects the first .listProduct
element. This is why only one product is clickable.productId
assignment – Inside the click event, you're using data.id
, which always refers to the last iteration value. This is why the wrong product ID is being used.So i recreated the flow:
querySelectorAll
to select all buttons and add event listeners properly.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Cards</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="row card-parent"></div>
</div>
<script>
let cardData = [
{ id: 1, imgFile: 'images/products/marievi5.jpg', heading: 'Marievi the Influencer', body: 'This is card body', price: 150 },
{ id: 2, imgFile: 'images/products/rock1.jpg', heading: 'Card 2', body: 'This is card body', price: 200 },
{ id: 3, imgFile: 'images/products/marievi5.jpg', heading: 'Card 3', body: 'This is card body', price: 400 },
{ id: 4, imgFile: 'images/products/marievi5.jpg', heading: 'Card 4', body: 'This is card body', price: 300 }
];
const createCard = () => {
let cardContainer = document.querySelector('.card-parent');
cardContainer.innerHTML = '';
cardData.forEach((data) => {
let card = document.createElement('div');
card.classList.add('col-md-4', 'mb-4');
card.innerHTML = `
<div class="card shadow-sm">
<img class="card-img-top" src="${data.imgFile}" alt="Product Image">
<div class="card-body">
<h5 class="card-title fw-bold">${data.heading}</h5>
<p class="card-text text-muted">${data.body}</p>
<div class="d-flex justify-content-between align-items-center">
<span class="product-price fw-bold">$${data.price}</span>
<button class="btn btn-primary view-details-btn" data-product-id="${data.id}">View Details</button>
</div>
</div>
</div>
`;
cardContainer.appendChild(card); // use appendChild here instead of innerHtml, because innerHtml will remove the existing cards
});
document.querySelectorAll('.view-details-btn').forEach((button) => { // Here i used View Details button class instead of card class
button.addEventListener('click', function () {
let productId = this.getAttribute('data-product-id'); // taking the all card buttons and add event listener to listen click event and then take id using getAttribute
window.location.href = `ProductDetails1.html?id=${productId}`;
});
});
}
createCard();
</script>
</body>
</html>
document.querySelector('.listProduct')
will always return the first matching element it finds within the document. – C3roe Commented Feb 4 at 12:38let productId = data.id; // This should not be undefined
-data
does not exist within the scope of your click handler callback function. – C3roe Commented Feb 4 at 12:40[<>]
and provide a minimal reproducible example using RELEVANT RENDERED HTML and RELEVANT JS – mplungjan Commented Feb 4 at 13:09