[FIX] website_sale_aplicoop: prevent grid destruction on event listener attachment
The _attachEventListeners() function was cloning the products-grid element without its children (cloneNode(false)) to remove duplicate event listeners. This destroyed all loaded products every time the function was called. Solution: Use a flag (_delegationListenersAttached) to prevent adding duplicate event listeners instead of cloning and replacing the grid node. This fixes the issue where products would disappear ~1-2 seconds after page load.
This commit is contained in:
parent
b15e9bc977
commit
b07b7dc671
6 changed files with 521 additions and 218 deletions
|
|
@ -45,6 +45,10 @@
|
|||
|
||||
console.log("Initializing cart for order:", this.orderId);
|
||||
|
||||
// Attach event listeners FIRST (doesn't depend on translations)
|
||||
this._attachEventListeners();
|
||||
console.log("[groupOrderShop] Event listeners attached");
|
||||
|
||||
// Wait for i18nManager to load translations from server
|
||||
i18nManager
|
||||
.init()
|
||||
|
|
@ -52,8 +56,6 @@
|
|||
console.log("[groupOrderShop] Translations loaded from server");
|
||||
self.labels = i18nManager.getAll();
|
||||
|
||||
// Initialize event listeners and state after translations are ready
|
||||
self._attachEventListeners();
|
||||
self._loadCart();
|
||||
self._checkConfirmationMessage();
|
||||
self._initializeTooltips();
|
||||
|
|
@ -603,12 +605,70 @@
|
|||
_attachEventListeners: function () {
|
||||
var self = this;
|
||||
|
||||
// Helper function to round decimals correctly
|
||||
function roundDecimal(value, decimals) {
|
||||
var factor = Math.pow(10, decimals);
|
||||
return Math.round(value * factor) / factor;
|
||||
}
|
||||
|
||||
// ============ ATTACH CHECKOUT BUTTONS (ALWAYS, on any page) ============
|
||||
// These buttons exist on checkout page, not on cart pages
|
||||
if (!this._cartCheckoutListenersAttached) {
|
||||
console.log("[_attachEventListeners] Attaching checkout button listeners...");
|
||||
|
||||
// Button to save as draft (in checkout page)
|
||||
var saveBtn = document.getElementById("save-order-btn");
|
||||
console.log("[_attachEventListeners] save-order-btn found:", !!saveBtn);
|
||||
|
||||
if (saveBtn) {
|
||||
saveBtn.addEventListener("click", function (e) {
|
||||
console.log("[CLICK] save-order-btn clicked");
|
||||
e.preventDefault();
|
||||
self._saveOrderDraft();
|
||||
});
|
||||
}
|
||||
|
||||
// Confirm order button (in checkout page)
|
||||
var confirmBtn = document.getElementById("confirm-order-btn");
|
||||
console.log("[_attachEventListeners] confirm-order-btn found:", !!confirmBtn);
|
||||
|
||||
if (confirmBtn) {
|
||||
confirmBtn.addEventListener("click", function (e) {
|
||||
console.log("[CLICK] confirm-order-btn clicked");
|
||||
e.preventDefault();
|
||||
self._confirmOrder();
|
||||
});
|
||||
}
|
||||
|
||||
// Button to reload from draft (in My Cart header - cart pages)
|
||||
var reloadCartBtn = document.getElementById("reload-cart-btn");
|
||||
console.log("[_attachEventListeners] reload-cart-btn found:", !!reloadCartBtn);
|
||||
|
||||
if (reloadCartBtn) {
|
||||
reloadCartBtn.addEventListener("click", function (e) {
|
||||
console.log("[CLICK] reload-cart-btn clicked");
|
||||
e.preventDefault();
|
||||
self._loadDraftCart();
|
||||
});
|
||||
}
|
||||
|
||||
this._cartCheckoutListenersAttached = true;
|
||||
console.log("[_attachEventListeners] Checkout listeners attached (one-time)");
|
||||
}
|
||||
|
||||
// ============ LAZY LOADING: Load More Button ============
|
||||
this._attachLoadMoreListener();
|
||||
|
||||
// Adjust quantity step based on UoM category
|
||||
// Categories without decimals (per unit): "Unit", "Units", etc.
|
||||
// Categories with decimals: "Weight", "Volume", "Length", etc.
|
||||
// ============ USE EVENT DELEGATION FOR QUANTITY & CART BUTTONS ============
|
||||
// This way, new products loaded via AJAX will automatically have listeners
|
||||
var productsGrid = document.getElementById("products-grid");
|
||||
|
||||
if (!productsGrid) {
|
||||
console.log("[_attachEventListeners] No products-grid found (checkout page?)");
|
||||
return;
|
||||
}
|
||||
|
||||
// First, adjust quantity steps for all existing inputs
|
||||
var unitInputs = document.querySelectorAll(".product-qty");
|
||||
console.log("=== ADJUSTING QUANTITY STEPS ===");
|
||||
console.log("Found " + unitInputs.length + " quantity inputs");
|
||||
|
|
@ -638,141 +698,108 @@
|
|||
}
|
||||
console.log("=== END ADJUSTING QUANTITY STEPS ===");
|
||||
|
||||
// Botones + y - para aumentar/disminuir cantidad
|
||||
// Helper function to round decimals correctly
|
||||
function roundDecimal(value, decimals) {
|
||||
var factor = Math.pow(10, decimals);
|
||||
return Math.round(value * factor) / factor;
|
||||
// IMPORTANT: Do NOT clone the grid node - this destroys all products!
|
||||
// Instead, use a flag to prevent adding duplicate event listeners
|
||||
if (productsGrid._delegationListenersAttached) {
|
||||
console.log(
|
||||
"[_attachEventListeners] Grid delegation listeners already attached, skipping"
|
||||
);
|
||||
return;
|
||||
}
|
||||
productsGrid._delegationListenersAttached = true;
|
||||
console.log("[_attachEventListeners] Attaching grid delegation listeners (one-time)");
|
||||
|
||||
// Remove old listeners by cloning elements (to avoid duplication)
|
||||
var decreaseButtons = document.querySelectorAll(".qty-decrease");
|
||||
for (var k = 0; k < decreaseButtons.length; k++) {
|
||||
var newBtn = decreaseButtons[k].cloneNode(true);
|
||||
decreaseButtons[k].parentNode.replaceChild(newBtn, decreaseButtons[k]);
|
||||
}
|
||||
// Quantity decrease button (via event delegation)
|
||||
productsGrid.addEventListener("click", function (e) {
|
||||
var decreaseBtn = e.target.closest(".qty-decrease");
|
||||
if (!decreaseBtn) return;
|
||||
|
||||
var increaseButtons = document.querySelectorAll(".qty-increase");
|
||||
for (var k = 0; k < increaseButtons.length; k++) {
|
||||
var newBtn = increaseButtons[k].cloneNode(true);
|
||||
increaseButtons[k].parentNode.replaceChild(newBtn, increaseButtons[k]);
|
||||
}
|
||||
e.preventDefault();
|
||||
var productId = decreaseBtn.getAttribute("data-product-id");
|
||||
var input = document.getElementById("qty_" + productId);
|
||||
if (!input) return;
|
||||
|
||||
// Ahora asignar nuevos listeners
|
||||
decreaseButtons = document.querySelectorAll(".qty-decrease");
|
||||
for (var k = 0; k < decreaseButtons.length; k++) {
|
||||
decreaseButtons[k].addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
var productId = this.getAttribute("data-product-id");
|
||||
var input = document.getElementById("qty_" + productId);
|
||||
if (!input) return;
|
||||
var step = parseFloat(input.step) || 1;
|
||||
var currentValue = parseFloat(input.value) || 0;
|
||||
var min = parseFloat(input.min) || 0;
|
||||
var newValue = Math.max(min, roundDecimal(currentValue - step, 1));
|
||||
|
||||
var step = parseFloat(input.step) || 1;
|
||||
var currentValue = parseFloat(input.value) || 0;
|
||||
var min = parseFloat(input.min) || 0;
|
||||
var newValue = Math.max(min, roundDecimal(currentValue - step, 1));
|
||||
// Si es unidad, mostrar como entero
|
||||
if (input.dataset.isUnit === "true") {
|
||||
input.value = Math.floor(newValue);
|
||||
} else {
|
||||
input.value = newValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Si es unidad, mostrar como entero
|
||||
if (input.dataset.isUnit === "true") {
|
||||
input.value = Math.floor(newValue);
|
||||
} else {
|
||||
input.value = newValue;
|
||||
}
|
||||
// Quantity increase button (via event delegation)
|
||||
productsGrid.addEventListener("click", function (e) {
|
||||
var increaseBtn = e.target.closest(".qty-increase");
|
||||
if (!increaseBtn) return;
|
||||
|
||||
e.preventDefault();
|
||||
var productId = increaseBtn.getAttribute("data-product-id");
|
||||
var input = document.getElementById("qty_" + productId);
|
||||
if (!input) return;
|
||||
|
||||
var step = parseFloat(input.step) || 1;
|
||||
var currentValue = parseFloat(input.value) || 0;
|
||||
var newValue = roundDecimal(currentValue + step, 1);
|
||||
|
||||
// Si es unidad, mostrar como entero
|
||||
if (input.dataset.isUnit === "true") {
|
||||
input.value = Math.floor(newValue);
|
||||
} else {
|
||||
input.value = newValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Add to cart button (via event delegation)
|
||||
productsGrid.addEventListener("click", function (e) {
|
||||
var cartBtn = e.target.closest(".add-to-cart-btn");
|
||||
if (!cartBtn) return;
|
||||
|
||||
e.preventDefault();
|
||||
var form = cartBtn.closest(".add-to-cart-form");
|
||||
var productId = form.getAttribute("data-product-id");
|
||||
var productName = form.getAttribute("data-product-name") || "Product";
|
||||
var productPrice = parseFloat(form.getAttribute("data-product-price")) || 0;
|
||||
var quantityInput = form.querySelector(".product-qty");
|
||||
var quantity = quantityInput ? parseFloat(quantityInput.value) : 1;
|
||||
|
||||
console.log("Adding:", {
|
||||
productId: productId,
|
||||
productName: productName,
|
||||
productPrice: productPrice,
|
||||
quantity: quantity,
|
||||
});
|
||||
}
|
||||
|
||||
increaseButtons = document.querySelectorAll(".qty-increase");
|
||||
for (var k = 0; k < increaseButtons.length; k++) {
|
||||
increaseButtons[k].addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
var productId = this.getAttribute("data-product-id");
|
||||
var input = document.getElementById("qty_" + productId);
|
||||
if (!input) return;
|
||||
|
||||
var step = parseFloat(input.step) || 1;
|
||||
var currentValue = parseFloat(input.value) || 0;
|
||||
var newValue = roundDecimal(currentValue + step, 1);
|
||||
|
||||
// Si es unidad, mostrar como entero
|
||||
if (input.dataset.isUnit === "true") {
|
||||
input.value = Math.floor(newValue);
|
||||
} else {
|
||||
input.value = newValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Botones de agregar al carrito
|
||||
var buttons = document.querySelectorAll(".add-to-cart-btn");
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
buttons[i].addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
var form = this.closest(".add-to-cart-form");
|
||||
var productId = form.getAttribute("data-product-id");
|
||||
var productName = form.getAttribute("data-product-name") || "Product";
|
||||
var productPrice = parseFloat(form.getAttribute("data-product-price")) || 0;
|
||||
var quantityInput = form.querySelector(".product-qty");
|
||||
var quantity = quantityInput ? parseFloat(quantityInput.value) : 1;
|
||||
|
||||
console.log("Adding:", {
|
||||
productId: productId,
|
||||
productName: productName,
|
||||
productPrice: productPrice,
|
||||
quantity: quantity,
|
||||
});
|
||||
|
||||
if (quantity > 0) {
|
||||
self._addToCart(productId, productName, productPrice, quantity);
|
||||
} else {
|
||||
var labels = self._getLabels();
|
||||
self._showNotification(
|
||||
labels.invalid_quantity || "Please enter a valid quantity",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (quantity > 0) {
|
||||
self._addToCart(productId, productName, productPrice, quantity);
|
||||
} else {
|
||||
var labels = self._getLabels();
|
||||
self._showNotification(
|
||||
labels.invalid_quantity || "Please enter a valid quantity",
|
||||
"warning"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Button to save cart as draft (in My Cart header)
|
||||
var savCartBtn = document.getElementById("save-cart-btn");
|
||||
if (savCartBtn) {
|
||||
// Remove old listeners by cloning
|
||||
var savCartBtnNew = savCartBtn.cloneNode(true);
|
||||
savCartBtn.parentNode.replaceChild(savCartBtnNew, savCartBtn);
|
||||
savCartBtnNew.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
self._saveCartAsDraft();
|
||||
});
|
||||
}
|
||||
// Only attach ONCE
|
||||
if (!this._cartCheckoutListenersAttached) {
|
||||
console.log("[_attachEventListeners] Attempting to attach checkout listeners...");
|
||||
|
||||
// Button to reload from draft (in My Cart header)
|
||||
var reloadCartBtn = document.getElementById("reload-cart-btn");
|
||||
if (reloadCartBtn) {
|
||||
// Remove old listeners by cloning
|
||||
var reloadCartBtnNew = reloadCartBtn.cloneNode(true);
|
||||
reloadCartBtn.parentNode.replaceChild(reloadCartBtnNew, reloadCartBtn);
|
||||
reloadCartBtnNew.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
self._loadDraftCart();
|
||||
});
|
||||
}
|
||||
var savCartBtn = document.getElementById("save-cart-btn");
|
||||
console.log("[_attachEventListeners] save-cart-btn found:", !!savCartBtn);
|
||||
|
||||
// Button to save as draft
|
||||
var saveBtn = document.getElementById("save-order-btn");
|
||||
if (saveBtn) {
|
||||
saveBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
self._saveOrderDraft();
|
||||
});
|
||||
}
|
||||
|
||||
// Confirm order button
|
||||
var confirmBtn = document.getElementById("confirm-order-btn");
|
||||
if (confirmBtn) {
|
||||
confirmBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
self._confirmOrder();
|
||||
});
|
||||
if (savCartBtn) {
|
||||
savCartBtn.addEventListener("click", function (e) {
|
||||
console.log("[CLICK] save-cart-btn clicked");
|
||||
e.preventDefault();
|
||||
self._saveCartAsDraft();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1475,7 +1502,7 @@
|
|||
},
|
||||
|
||||
_saveOrderDraft: function () {
|
||||
console.log("Saving order as draft:", this.orderId);
|
||||
console.log("[_saveOrderDraft] Starting - this.orderId:", this.orderId);
|
||||
|
||||
var self = this;
|
||||
var items = [];
|
||||
|
|
@ -1979,13 +2006,10 @@
|
|||
console.log("cart-items-container found:", !!cartContainer);
|
||||
console.log("confirm-order-btn found:", !!confirmBtn);
|
||||
|
||||
if (cartContainer || confirmBtn) {
|
||||
console.log("Calling init()");
|
||||
var result = window.groupOrderShop.init();
|
||||
console.log("init() result:", result);
|
||||
} else {
|
||||
console.warn("No elements found to initialize cart");
|
||||
}
|
||||
// Always initialize - it handles both cart pages and checkout pages
|
||||
console.log("Calling init()");
|
||||
var result = window.groupOrderShop.init();
|
||||
console.log("init() result:", result);
|
||||
});
|
||||
|
||||
// Handle confirm order buttons in portal (My Orders page)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue