0

I am still in the process of writing this, but I am now in a slump. This might be a novice question but is there a way to click on the image itself? I was hoping to incorprate it as an e-commerce website [add to cart] feature. However, the alert only appears when I click outside the image, and not on the image itself. Any advices and suggestions will be very much appreciated!

let listProductHTML = document.querySelector('.ProductContainer');

let listProduct = [];

const addProductToHTML = () => {
    listProductHTML.innerHTML = '';
    if(listProduct.length > 0){
        listProduct.forEach(Product => {
            let newProduct = document.createElement('div');
            newProduct.classList.add('iconProduct');
            newProduct.dataset.id = Product.id;
            newProduct.innerHTML = `
                <img alt="Product image"
                src="${Product.image}" width="128" height="128">
                <p>${Product.name}</p>
            `;
            listProductHTML.appendChild(newProduct);
        })
    }
}

listProductHTML.addEventListener('click', (event) => {
    let positionClick = event.target;
    let Product_id = positionClick.dataset.id;
    if(positionClick.classList.contains('iconProduct')){
        let Product_id = positionClick.dataset.id;
        alert(Product_id);
    }

//I am unable to move forward at this point

})


const initApp = () => {
    //get data from json
    fetch('Products.json')
    .then(response => response.json())
    .then(data => {
        listProduct = data;
        addProductToHTML();
    })
}
initApp();
New contributor
UnOne SciDiez is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
0

2 Answers 2

1

You’re very close. The problem is that your click handler is attached to .ProductContainer, but inside the handler you’re checking the class on event.target.

When you click on the image or the <p>, event.target is that inner element, not the .iconProduct div, so this check fails:

if (positionClick.classList.contains('iconProduct')) {

A simple way to fix this is to walk up to the closest .iconProduct element and use that:

listProductHTML.addEventListener('click', (event) => {
    const productEl = event.target.closest('.iconProduct');
    if (!productEl) return; // click was outside a product

    const productId = productEl.dataset.id;
    alert(productId);
});

Now clicking the image, the name, or any empty space inside the product card will all trigger the alert with the correct data-id.

New contributor
Random3c0d3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
Sign up to request clarification or add additional context in comments.

1 Comment

I never thought of that! I appreciate you greatly for allowing me to realize where I fell short. It was wrong of me to assume that attaching the click handler to the .ProductContainer div would enable it to identify any element within it.
1

You are indeed successfully clicking on the img element. However, this evaluates to undefined:

let Product_id = positionClick.dataset.id;

And this evaluates to false so the if block doesn't execute:

if(positionClick.classList.contains('iconProduct'))

This is because the dataset.id and the class are added to the div, not to the img.

You can create the img (and the p) the same way you create the div, appending each to their respective containers, to make the code a little cleaner to work with. Then, at least just to demonstrate, you can add the dataset.id and class to the img as well. For example:

const addProductToHTML = () => {
  listProductHTML.innerHTML = '';
  if(listProduct.length > 0){
    listProduct.forEach(Product => {
      let newProduct = document.createElement('div');
      newProduct.classList.add('iconProduct');
      newProduct.dataset.id = Product.id;

      let newImage = document.createElement('img');
      newImage.classList.add('iconProduct'); // <-- here, so the if block can execute in the click handler
      newImage.dataset.id = Product.id;      // <-- here, so the value can be read in the click handler
      newImage.alt = 'Product image';
      newImage.src = Product.image;
      newImage.width = 128;
      newImage.height = 128;

      let newText = document.createElement('p');
      newText.innerText = Product.name;

      newProduct.appendChild(newImage);
      newProduct.appendChild(newText);
      listProductHTML.appendChild(newProduct);
    })
  }
}

Since this adds a class to the image, your styling may change. (We don't have a complete example, so this is mainly speculation.) So there will likely need to be some adjustments made. You could perhaps use a different class on the image and check for that in the click handler, for example.

1 Comment

I appreciate the substantial demonstration! I know this may seem like another novice question, but does that mean that the data-id does not automatically include the elements within the div?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.