JavaScript onclick event gets the wrong id from dynamically generated html element

别说谁变了你拦得住时间么 提交于 2021-01-29 16:26:57

问题


Using mongodb and ejs in a NodeJS application, I have created a function that loops through products in the shopping cart and dynamically shows each one of them on the page, inside a table.

I am trying to create a quantity update function that uses an input field to take the quantity and a button to update the database.

My HTML:

<tbody class="product-container">
    <!-- loop through each product -->
    <%  products.forEach (function(element) { %>
        <tr valign="top" class="cart-p-list">
            <!-- get individual unique ID for each product -->
            <input type="hidden" class="id" value="<%= element.item._id %>">

            <td class="col-qty cart-p-qty nowrap" align="right">
                <div class="proopc-input-append">
                    <!-- input for quantity and update button -->
                    <input type="number" class="input-ultra-mini proopc-qty-input qty" size="1" maxlength="4" name="quantity" value="<%= element.qty %>" data-quantity="<%= element.qty %>" step="1" min="1" max="50">
                    <button class="proopc-btn proopc-task-updateqty updateproduct" name="updatecart.0" title="Update Quantity In Cart"><i class="proopc-icon-refresh"></i></button>
                </div>
            </td>
        </tr>
        <% }); %>

For test purposes, the javascript is in a <script> tag at the bottom of the page.

My JavaScript code:

window.addEventListener('load', function() {
    {
        // Update Quantity of product in shopping cart
        const block = document.querySelector('.product-container');


        block.addEventListener('click', function(e) {
            if (e.target.classList.contains('updateproduct')) {
                console.log(e);

                let id = e.target.parentNode.parentNode.parentNode.parentNode.querySelector('.id').value;
                let qty = +e.target.parentNode.querySelector('.qty').value;
                console.log(id);

                fetch(`/update/${id}/${qty}`, {
                    method: 'GET'
                }).then((res) => res.text());
            }
        });
    }
});

The code fetches the following GET request from my cart.js:

router.get('/update/:id/:qty', function (req, res, next) {
    let productId = req.params.id;
    let quantity = +req.params.qty;

    let cart = new Cart(req.session.cart ? req.session.cart : {});
    cart.update(productId, quantity);
    req.session.cart = cart;
    res.redirect('back');
});

And my cart model:

module.exports = function Cart(oldCart) {
    this.items = oldCart.items || {};
    this.totalQty = oldCart.totalQty || 0;
    this.totalPrice = oldCart.totalPrice || 0;

    this.update = function (id, quantity) {
        let currentQuantity = this.items[id].qty;
        let newQuantity = this.items[id].qty = quantity;
        let currentPrice = this.items[id].price;
        let newPrice = this.items[id].item.price * quantity;;
        this.items[id].price = this.items[id].item.price * quantity;
        this.totalQty -= currentQuantity;
        this.totalQty += newQuantity;
        this.totalPrice -= currentPrice;
        this.totalPrice += newPrice;

    };

    this.generateArray = function () {
        let arr = [];
        for (let id in this.items) {
            arr.push(this.items[id]);
        }
        return arr;
    };
};

The logic is working fine. The product is being updated, the price and quantity are correct. The total price and quantity are also correct.

However, if I have more than one product in the cart (two different products), if I try to update the quantity of the second product (or any product that's not the first one), on refresh, the quantity of the first product is updated instead.

This is caused because the eventlistener that updates the quantity, always takes the id of the first dynamically generated item on the page instead of the one that I am trying to update the quantity of.

This must be caused because of looping through the products in the ejs file, so I suspect I need to do some sort of looping in the js function to get the correct id, but I am unsure of this.


回答1:


I figured out a solution.

I created a function that checks the position of the child (tr in this case) of a parent (tbody with the class product-container in my case) of which the update request was declared.

This is the loop that finds the index:

for (let i = 0, len = block.children.length; i < len; i++) {

    (function(index) {
        block.children[i].onclick = function() {
            console.log(index);
        }
    })(i);
}

This is how I implemented it in my code:

document.addEventListener('DOMContentLoaded', function() {
    {
        // Update Quantity of product in shopping cart
        const block = document.querySelector('.product-container');
        // Fetch an array of all ids
        let ids = document.querySelectorAll('.id');
        // Create a function that shows the index of the child of the parent block
        for (let i = 0, len = block.children.length; i < len; i++) {
            (function(index) {
                block.children[i].onclick = function(e) {
                    if (e.target && e.target.classList.contains('updateproduct')) {
                        // ID now equals the id of the clicked child of the container
                        let id = ids[index].value;
                        let qty = +e.target.parentNode.querySelector('.qty').value;

                        fetch(`/update/${id}/${qty}`, {
                            method: 'GET'
                        }).then((res) => res.text()).then(() => window.history.go());
                    }
                }
            })(i);
        }
    }
});


来源:https://stackoverflow.com/questions/58716454/javascript-onclick-event-gets-the-wrong-id-from-dynamically-generated-html-eleme

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!