I’m working on a shopping cart functionality for a fictitious online store. The core of this functionality is a Cart
class that manages the information and performs calculations. This class doesn’t interact with the HTML document or the DOM, it simply performs calculations.
The Cart
class haves methods to manage products. Each product has a SKU, title, price properties and I’m trying to add a quantity property too but it’s not working I think. I have two buttons, addButton
and subtractButton
, for each product to increase or decrease the quantity.
I want to achieve the following:
- When the
addButton
is clicked, the quantity of the product should increase by 1, and the total price for that SKU should be updated in thetotal-SKU
span. - When the
subtractButton
is clicked, the quantity of the product should decrease by 1 (if it’s greater than 0), and the total price for that SKU should be updated in thetotal-SKU
span. - The total price of all SKUs should be calculated and displayed in the
total
div.
Here’s the code in jsFiddle: https://jsfiddle.net/mlpz2/edfjLhb2
Here’s the code here:
class Cart {
constructor(products, currency) {
this.products = [];
this.currency = "";
}
initializeQuantity = () => {
for (let product of this.products) {
product.quantity = 0; // Initialize quantity to 0 for each product
}
console.log(this.products.quantity);
};
updateUnits = (sku, units) => {
// Update the number of units to be purchased for a product
let product = this.products.find((p) => p.sku === sku);
if (product) {
product.quantity = units;
console.log(this.products.quantity);
} else {
this.products.push({ sku: sku, quantity: units });
}
};
getProductInformation = (sku) => {
// Returns the data of a product along with the selected units
// For example:
// {
// "sku": "0K3QOSOV4V",
// "quantity": 3
// }
return this.products.find((p) => p.sku === sku);
};
getAllProducts = () => {
return this.products;
};
getCart = () => {
// Returns information about the products added to the cart
// Along with the calculated total of all products
// For example:
// {
// "total": "5820",
// "currency: "€",
// "products" : [
// {
// "sku": "0K3QOSOV4V"
// ..
// }
// ]}
let total = this.products.reduce(
(sum, p) => sum + p.quantity * p.price,
0
);
return { total: total, currency: this.currency, products: this.products };
};
}
let cart = new Cart();
cart.initializeQuantity();
const getProductsData = async () => {
let response = await fetch(
"https://jsonblob.com/api/jsonBlob/1241305513466912768"
);
let data = await response.json();
console.log(data);
return data; // return the full response
};
const showProducts = (products) => {
console.log(products);
let productsContainer = document.getElementById("productsContainer");
for (let product of products) {
let quantity = product.quantity || 0; // Initialize quantity here
let productElement = document.createElement("div");
productElement.innerHTML = `
<h2>${product.title}</h2>
<p>Ref: ${product.SKU}</p>
<p>Price: ${product.price}€/unit</p>
<button class="substractButton">-</button>
<span id="quantity-${product.SKU}">${quantity}</span>
<button class="addButton">+</button>
<p>Total: <span id="total-${product.SKU}">0</span>€</p>
`;
productElement.className = "product";
productsContainer.appendChild(productElement);
let addButtons = productElement.querySelectorAll(".addButton");
for (let i = 0; i < addButtons.length; i++) {
addButtons[i].addEventListener('click', () => updateQuantity(product.SKU, 1));
}
console.log(addButtons);
let subtractButtons = productElement.querySelectorAll(".substractButton");
for (let i = 0; i < subtractButtons.length; i++) {
subtractButtons[i].addEventListener('click', () => updateQuantity(product.SKU, -1));
console.log(typeof subtractButtons[i], subtractButtons[i]);
}
}
console.log(productsContainer);
};
const updateTotal = (sku) => {
let products = cart.getAllProducts(); // Assuming getCart returns an array of products
let total = 0;
console.log(products); // Check if the products are being fetched correctly
for (let product of products) {
total += product.quantity * product.price;
}
document.getElementById('total').textContent = `TOTAL: ${total}`; // Assuming 'total' is the id of the element displaying the total price
};
const updateQuantity = (sku, change) => {
let product = cart.getProductInformation(sku);
if (product) {
product.quantity += change;
if (product.quantity < 0) {
// Ensure the quantity doesn't go below 0
product.quantity = 0;
}
document.getElementById(`quantity-${sku}`).textContent = product.quantity;
document.getElementById(`total-${sku}`).textContent =
product.quantity * product.price;
updateTotal();
}
};
getProductsData().then((data) => {
if (data && data.products) {
cart.products = data.products;
cart.products = data.products.map((product) => {
return {
...product,
price: parseFloat(product.price),
};
}); // assign the currency to the cart object
showProducts(cart.products);
updateTotal();
} else {
console.error("Failed to fetch products");
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="productsContainer">
<div id="total">
<!-- The total will be shown here -->
</div>
</div>
<script src="script.js"></script>
</body>
</html>
#productsContainer {
display: flex;
flex-direction: column;
flex-wrap: wrap;
margin-top: 20px;
position: relative;
}
.product {
width: 200px;
margin: 10px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
text-align: center;
}
#total {
position: absolute;
font-size: 20px;
font-weight: bold;
bottom: -20px;
left: 10px;
background-color: #ececec;
}
@media (min-width: 768px) {
#productsContainer {
flex-direction: row;
}
}
The products are fetched from an API. I’m using jsonblob.com(https://jsonblob.com/api/jsonBlob/1241305513466912768) to create a mock API.
{
"currency": "€",
"products": [
{
"SKU": "0K3QOSOV4V",
"title": "iFhone 13 Pro",
"price": "938.99"
},
{
"SKU": "TGD5XORY1L",
"title": "Cargador",
"price": "49.99"
},
{
"SKU": "IOKW9BQ9F3",
"title": "Funda de piel",
"price": "79.99"
}
]
}
I think I’m not sure how to:
- Create new elements in the DOM for the product list.
- Listen for events to update the number of units for each product.
- Update the total price in the DOM whenever a change is made.
I’m not sure how to create the event listeners for the addButton
and subtractButton
and how to update the quantity and total price in the DOM.
I’m also open to any suggestions for improving the code. Any help would be appreciated!
Thank you for reading 🙂
2
Answers
Add the event listener to all the buttons seperately and check the events with the id for updating specific elements.
hope this helps.
After being through your code throughly, I’ve found this two major fixes
p.sku
you are accessing the invalid property of product through the class, so just change it top.SKU
p.quantity
is not in initial product object that why it showsNAN
it can be fixed by adding that while initialising so you won’t need anyif
condition to check that.Also some recommendations, you won’t need
querySelectorAll
since there is only one.addButton
, theforEach
will alway run once. Instead trygetElementsByClassName
orquerySelector
JSFIDDLE