Reputation: 4563
Not so sure why I could not create click event handler from getElementsByClassName. I could populate and see all the rendered html for all the products with class name AddToCart
for the button. But addToCart
is null at var addToCart = document.getElementsByClassName("AddToCart");
var productList = [
{ id: 101, product: "Logitech Mouse", unitprice: 45.0 },
{ id: 102, product: "Logitech Keyboard", unitprice: 50.0 },
{ id: 103, product: "HP Mouse", unitprice: 35.0 }
];
const populateProducts = object => {
// Start our HTML
var html = "";
debugger;
// Loop through members of the object
object.forEach(function(item) {
html += `<div class="column"><div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button class=AddToCart>Add to Cart</button></p></div></div>`;
});
debugger;
var addToCart = document.getElementsByClassName("AddToCart");
Array.prototype.forEach.call(addToCart, function(element) {
element.addEventListener("click", function() {
console.log(element);
});
});
return html;
};
window.addEventListener("load", function() {
document.getElementById("productRow").innerHTML = populateProducts(
productList
);
});
<div id="productRow"></div>
And how do I grab item.id
upon clicking "AddToCart" button?
Upvotes: 1
Views: 46
Reputation: 371193
The elements you want are not in the DOM - you've only created a string, which happens to contain HTML markup, but the elements are not in the DOM, so they can't be selected with getElementsByClassName
(or anything else) yet.
Instead of creating just a string, consider create the actual elements with createElement
, and then by appending each element to a container. Then you can use selection methods on the created element to get to the button, and add the event listeners:
var productList = [{
id: 101,
product: "Logitech Mouse",
unitprice: 45.0
},
{
id: 102,
product: "Logitech Keyboard",
unitprice: 50.0
},
{
id: 103,
product: "HP Mouse",
unitprice: 35.0
}
];
const populateProducts = (container, arrOfObjects) => {
// Start our HTML
var html = "";
debugger;
// Loop through members of the object
arrOfObjects.forEach(function(item) {
const newDiv = document.createElement('div');
newDiv.className = 'column';
newDiv.innerHTML = `<div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button>Add to Cart</button></p></div>`;
newDiv.querySelector('button').addEventListener('click', () => {
console.log(item.id);
});
container.appendChild(newDiv);
});
};
window.addEventListener("load", function() {
populateProducts(document.getElementById("productRow"), productList);
});
<div id="productRow"></div>
Upvotes: 1
Reputation: 1075755
You're trying to hook up the event handler before the elements exist in the DOM. You need to move that code hooking up the handlers to after the code assigning the HTML to innerHTML
.
Then, you can store the item ID as a data-*
attribute on the button, and access it via .getAttribute("data-id")
(or .dataset.id
on modern browsers):
var productList = [
{ id: 101, product: "Logitech Mouse", unitprice: 45.0 },
{ id: 102, product: "Logitech Keyboard", unitprice: 50.0 },
{ id: 103, product: "HP Mouse", unitprice: 35.0 }
];
const populateProducts = object => {
// Start our HTML
var html = "";
// Loop through members of the object
object.forEach(function(item) {
html += `<div class="column"><div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button class=AddToCart data-id="${item.id}">Add to Cart</button></p></div></div>`;
});
return html;
};
window.addEventListener("load", function() {
document.getElementById("productRow").innerHTML = populateProducts(
productList
);
var addToCart = document.getElementsByClassName("AddToCart");
Array.prototype.forEach.call(addToCart, function(element) {
element.addEventListener("click", function() {
console.log("via getAttribute:", element.getAttribute("data-id"));
console.log("via dataset:", element.dataset.id);
});
});
});
<div id="productRow"></div>
Note that you don't need a separate event handler for each button, you can reuse a single function:
var productList = [
{ id: 101, product: "Logitech Mouse", unitprice: 45.0 },
{ id: 102, product: "Logitech Keyboard", unitprice: 50.0 },
{ id: 103, product: "HP Mouse", unitprice: 35.0 }
];
const populateProducts = object => {
// Start our HTML
var html = "";
// Loop through members of the object
object.forEach(function(item) {
html += `<div class="column"><div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button class=AddToCart data-id="${item.id}">Add to Cart</button></p></div></div>`;
});
return html;
};
window.addEventListener("load", function() {
document.getElementById("productRow").innerHTML = populateProducts(
productList
);
var addToCart = document.getElementsByClassName("AddToCart");
function handler() {
console.log("via getAttribute:", this.getAttribute("data-id"));
console.log("via dataset:", this.dataset.id);
}
Array.prototype.forEach.call(addToCart, function(element) {
element.addEventListener("click", handler);
});
});
<div id="productRow"></div>
Upvotes: 1