简体   繁体   中英

addEventListener problem during Iteration of an array[solved]

i'm building a project for my boot camp, and i'm stuck in a small quite annoying area. i have an api where i can make queries to amazon and display products, each product has its own "card" styling and along with it i push each product to an empty array inside the user class constructor if the user select that he wants to add that product to his "profile", within the user class i have a function called "displayProducts" which basically iterating over that products array, creating a div element, modifying the innerHTML of the element on each iteration and displaying it on the page. this is the function:

        const productSection = document.getElementById('userProducts')
        productSection.innerHTML = ``;
        let div = document.createElement('div')
        if (user.products.length > 0) {
            user.products.forEach((product) => {
                div.innerHTML += `
        <div class="card horizontal">
            <div class="card-image">
                <img src=${product.img}>
            </div>

            <div class="card-stacked">
                <div class = "card-content">
                <span class = "card-title"> ${product.title} </span> 
                <p> ${product.rating} rating, ${product.totalReviews} reviews </p>
                <span> Price:${product.price}</span>
            </div>

            <div class="card-action">
                <button class="btn delete-${product.asin}">delete</button> 
            </div>

        </div> 
        `
                deleteButton = div.querySelector(`.delete-${product.asin}`).addEventListener('click', user.delete.bind(product))
                productSection.appendChild(div);
            }

The problem is, while adding the event listener to each button - it's af it's only applying the event listener to the last product, even though on each stage it select the correct button, i have been at it for over two hours and i'm quite lost. How do i persist an event listener to each product card?

When you use container.innerHTML += , any existing listeners inside the container will be lost, since the container's contents get re-parsed from the beginning from the new HTML string. An alternative is to use insertAdjacentHTML , which does not corrupt existing elements:

div.insertAdjacentHTML('beforeend', `
  <div class="card horizontal">
    <div class="card-image">
        <img src=${product.img}>
  // etc

Then using addEventListener inside the loop will work.

But another issue I'm concerned with is your concatenation of the HTML string with the products data. Unless this data is trustworthy, your current code can result in arbitrary code execution, which is a security risk. Instead of interpolating inside the template literal directly. consider selecting the elements afterwards and assigning to their textContent (or other attribute) instead. For example, instead of:

<img src=${product.img}>

append the current <div> , then assign to the src later. Instead of insertAdjacentHTML :

const thisCard = div.appendChild(document.createElement('div'));
thisCard.className = 'card horizontal';
thisCard.innerHTML = `
    <div class="card-image">
        <img>
    </div>
    // etc
`;
thisCard.querySelector('img').src = product.img;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM