问题
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