curriculum/challenges/english/blocks/workshop-shopping-cart/63f03b1ed5ab15420c057463.md
Your final step is to make your clear button functional. Add a click event listener to the clearCartBtn. For the callback, you can pass in cart.clearCart directly.
However, doing so will not work, because the context of this will be the clearCartBtn element. You need to bind the clearCart method to the cart object.
You can do this by passing cart.clearCart.bind(cart) as the callback.
And with that, the shopping cart workshop is complete!
You should add an event listener to your clearCartBtn element.
assert.match(code, /clearCartBtn\.addEventListener\(/);
Your event listener should listen for the click event.
assert.match(code, /clearCartBtn\.addEventListener\(\s*('|"|`)click\1\s*,/);
Your event listener should take cart.clearCart.bind(cart) as the callback.
assert.match(code, /clearCartBtn\.addEventListener\(\s*('|"|`)click\1\s*,\s*cart\.clearCart\s*\.bind\(\s*cart\s*\)\s*\)/);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>freeCodeCamp Shopping Cart</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<header>
<h1 class="title">Desserts Page</h1>
</header>
<main>
<button id="cart-btn" type="button" class="btn">
<span id="show-hide-cart">Show</span> Cart
</button>
<div id="cart-container">
<button class="btn" id="clear-cart-btn">Clear Cart</button>
<div id="products-container"></div>
<p>Total number of items: <span id="total-items">0</span></p>
<p>Subtotal: <span id="subtotal">$0</span></p>
<p>Taxes: <span id="taxes">$0</span></p>
<p>Total: <span id="total">$0</span></p>
</div>
<div id="dessert-card-container"></div>
</main>
<script src="./script.js"></script>
</body>
</html>
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--black: #000;
--white: #fff;
--grey: #3b3b4f;
--golden-yellow: #fecc4c;
--yellow: #ffcc4c;
--gold: #feac32;
--orange: #ffac33;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.title {
color: var(--light-grey);
text-align: center;
margin: 25px 0;
}
#dessert-card-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
}
.dessert-card {
background-color: var(--light-grey);
padding: 15px;
text-align: center;
border-radius: 15px;
margin: 20px 10px;
}
.dessert-price {
font-size: 1.2rem;
}
.btn {
display: block;
cursor: pointer;
width: 100px;
color: var(--dark-grey);
background-color: var(--gold);
background-image: linear-gradient(var(--golden-yellow), var(--orange));
border-color: var(--gold);
border-width: 3px;
}
.btn:hover {
background-image: linear-gradient(var(--yellow), var(--dark-orange));
}
#cart-btn {
position: absolute;
top: 0;
right: 0;
}
.add-to-cart-btn {
margin: 30px auto 10px;
}
#cart-container {
display: none;
position: absolute;
top: 60px;
right: 0;
background-color: var(--light-grey);
width: 200px;
height: 400px;
border: 8px double var(--black);
border-radius: 15px;
text-align: center;
font-size: 1.2rem;
overflow-y: scroll;
}
.product {
margin: 25px 0;
}
.product-count {
display: inline-block;
margin-right: 10px;
}
.product-category {
margin: 10px 0;
}
@media (min-width: 768px) {
#dessert-card-container {
flex-direction: row;
}
.dessert-card {
flex: 1 0 21%;
}
#cart-container {
width: 300px;
}
}
const cartContainer = document.getElementById("cart-container");
const productsContainer = document.getElementById("products-container");
const dessertCards = document.getElementById("dessert-card-container");
const cartBtn = document.getElementById("cart-btn");
const clearCartBtn = document.getElementById("clear-cart-btn");
const totalNumberOfItems = document.getElementById("total-items");
const cartSubTotal = document.getElementById("subtotal");
const cartTaxes = document.getElementById("taxes");
const cartTotal = document.getElementById("total");
const showHideCartSpan = document.getElementById("show-hide-cart");
let isCartShowing = false;
const products = [
{
id: 1,
name: "Vanilla Cupcakes (6 Pack)",
price: 12.99,
category: "Cupcake",
},
{
id: 2,
name: "French Macaron",
price: 3.99,
category: "Macaron",
},
{
id: 3,
name: "Pumpkin Cupcake",
price: 3.99,
category: "Cupcake",
},
{
id: 4,
name: "Chocolate Cupcake",
price: 5.99,
category: "Cupcake",
},
{
id: 5,
name: "Chocolate Pretzels (4 Pack)",
price: 10.99,
category: "Pretzel",
},
{
id: 6,
name: "Strawberry Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 7,
name: "Chocolate Macarons (4 Pack)",
price: 9.99,
category: "Macaron",
},
{
id: 8,
name: "Strawberry Pretzel",
price: 4.99,
category: "Pretzel",
},
{
id: 9,
name: "Butter Pecan Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 10,
name: "Rocky Road Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 11,
name: "Vanilla Macarons (5 Pack)",
price: 11.99,
category: "Macaron",
},
{
id: 12,
name: "Lemon Cupcakes (4 Pack)",
price: 12.99,
category: "Cupcake",
},
];
products.forEach(
({ name, id, price, category }) => {
dessertCards.innerHTML += `
<div class="dessert-card">
<h2>${name}</h2>
<p class="dessert-price">$${price}</p>
<p class="product-category">Category: ${category}</p>
<button
id="${id}"
class="btn add-to-cart-btn">Add to cart
</button>
</div>
`;
}
);
class ShoppingCart {
constructor() {
this.items = [];
this.total = 0;
this.taxRate = 8.25;
}
addItem(id, products) {
const product = products.find((item) => item.id === id);
const { name, price } = product;
this.items.push(product);
const totalCountPerProduct = {};
this.items.forEach((dessert) => {
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
})
const currentProductCount = totalCountPerProduct[product.id];
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
currentProductCount > 1
? currentProductCountSpan.textContent = `${currentProductCount}x`
: productsContainer.innerHTML += `
<div id="dessert${id}" class="product">
<p>
<span class="product-count" id="product-count-for-id${id}"></span>${name}
</p>
<p>${price}</p>
</div>
`;
}
getCounts() {
return this.items.length;
}
clearCart() {
if (!this.items.length) {
alert("Your shopping cart is already empty");
return;
}
const isCartCleared = confirm(
"Are you sure you want to clear all items from your shopping cart?"
);
if (isCartCleared) {
this.items = [];
this.total = 0;
productsContainer.innerHTML = "";
totalNumberOfItems.textContent = 0;
cartSubTotal.textContent = 0;
cartTaxes.textContent = 0;
cartTotal.textContent = 0;
}
}
calculateTaxes(amount) {
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
}
calculateTotal() {
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
const tax = this.calculateTaxes(subTotal);
this.total = subTotal + tax;
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
cartTaxes.textContent = `$${tax.toFixed(2)}`;
cartTotal.textContent = `$${this.total.toFixed(2)}`;
return this.total;
}
};
const cart = new ShoppingCart();
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
[...addToCartBtns].forEach(
(btn) => {
btn.addEventListener("click", (event) => {
cart.addItem(Number(event.target.id), products);
totalNumberOfItems.textContent = cart.getCounts();
cart.calculateTotal();
})
}
);
cartBtn.addEventListener("click", () => {
isCartShowing = !isCartShowing;
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
cartContainer.style.display = isCartShowing ? "block" : "none";
});
--fcc-editable-region--
--fcc-editable-region--
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>freeCodeCamp Shopping Cart</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<header>
<h1 class="title">Desserts Page</h1>
</header>
<main>
<button id="cart-btn" type="button" class="btn">
<span id="show-hide-cart">Show</span> Cart
</button>
<div id="cart-container">
<button class="btn" id="clear-cart-btn">Clear Cart</button>
<div id="products-container"></div>
<p>Total number of items: <span id="total-items">0</span></p>
<p>Subtotal: <span id="subtotal">$0</span></p>
<p>Taxes: <span id="taxes">$0</span></p>
<p>Total: <span id="total">$0</span></p>
</div>
<div id="dessert-card-container"></div>
</main>
<script src="./script.js"></script>
</body>
</html>
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--black: #000;
--white: #fff;
--grey: #3b3b4f;
--golden-yellow: #fecc4c;
--yellow: #ffcc4c;
--gold: #feac32;
--orange: #ffac33;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.title {
color: var(--light-grey);
text-align: center;
margin: 25px 0;
}
#dessert-card-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
}
.dessert-card {
background-color: var(--light-grey);
padding: 15px;
text-align: center;
border-radius: 15px;
margin: 20px 10px;
}
.dessert-price {
font-size: 1.2rem;
}
.btn {
display: block;
cursor: pointer;
width: 100px;
color: var(--dark-grey);
background-color: var(--gold);
background-image: linear-gradient(var(--golden-yellow), var(--orange));
border-color: var(--gold);
border-width: 3px;
}
.btn:hover {
background-image: linear-gradient(var(--yellow), var(--dark-orange));
}
#cart-btn {
position: absolute;
top: 0;
right: 0;
}
.add-to-cart-btn {
margin: 30px auto 10px;
}
#cart-container {
display: none;
position: absolute;
top: 60px;
right: 0;
background-color: var(--light-grey);
width: 200px;
height: 400px;
border: 8px double var(--black);
border-radius: 15px;
text-align: center;
font-size: 1.2rem;
overflow-y: scroll;
}
.product {
margin: 25px 0;
}
.product-count {
display: inline-block;
margin-right: 10px;
}
.product-category {
margin: 10px 0;
}
@media (min-width: 768px) {
#dessert-card-container {
flex-direction: row;
}
.dessert-card {
flex: 1 0 21%;
}
#cart-container {
width: 300px;
}
}
const cartContainer = document.getElementById("cart-container");
const productsContainer = document.getElementById("products-container");
const dessertCards = document.getElementById("dessert-card-container");
const cartBtn = document.getElementById("cart-btn");
const clearCartBtn = document.getElementById("clear-cart-btn");
const totalNumberOfItems = document.getElementById("total-items");
const cartSubTotal = document.getElementById("subtotal");
const cartTaxes = document.getElementById("taxes");
const cartTotal = document.getElementById("total");
const showHideCartSpan = document.getElementById("show-hide-cart");
let isCartShowing = false;
const products = [
{
id: 1,
name: "Vanilla Cupcakes (6 Pack)",
price: 12.99,
category: "Cupcake",
},
{
id: 2,
name: "French Macaron",
price: 3.99,
category: "Macaron",
},
{
id: 3,
name: "Pumpkin Cupcake",
price: 3.99,
category: "Cupcake",
},
{
id: 4,
name: "Chocolate Cupcake",
price: 5.99,
category: "Cupcake",
},
{
id: 5,
name: "Chocolate Pretzels (4 Pack)",
price: 10.99,
category: "Pretzel",
},
{
id: 6,
name: "Strawberry Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 7,
name: "Chocolate Macarons (4 Pack)",
price: 9.99,
category: "Macaron",
},
{
id: 8,
name: "Strawberry Pretzel",
price: 4.99,
category: "Pretzel",
},
{
id: 9,
name: "Butter Pecan Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 10,
name: "Rocky Road Ice Cream",
price: 2.99,
category: "Ice Cream",
},
{
id: 11,
name: "Vanilla Macarons (5 Pack)",
price: 11.99,
category: "Macaron",
},
{
id: 12,
name: "Lemon Cupcakes (4 Pack)",
price: 12.99,
category: "Cupcake",
},
];
products.forEach(
({ name, id, price, category }) => {
dessertCards.innerHTML += `
<div class="dessert-card">
<h2>${name}</h2>
<p class="dessert-price">$${price}</p>
<p class="product-category">Category: ${category}</p>
<button
id="${id}"
class="btn add-to-cart-btn">Add to cart
</button>
</div>
`;
}
);
class ShoppingCart {
constructor() {
this.items = [];
this.total = 0;
this.taxRate = 8.25;
}
addItem(id, products) {
const product = products.find((item) => item.id === id);
const { name, price } = product;
this.items.push(product);
const totalCountPerProduct = {};
this.items.forEach((dessert) => {
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
})
const currentProductCount = totalCountPerProduct[product.id];
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
currentProductCount > 1
? currentProductCountSpan.textContent = `${currentProductCount}x`
: productsContainer.innerHTML += `
<div id="dessert${id}" class="product">
<p>
<span class="product-count" id="product-count-for-id${id}"></span>${name}
</p>
<p>${price}</p>
</div>
`;
}
getCounts() {
return this.items.length;
}
clearCart() {
if (!this.items.length) {
alert("Your shopping cart is already empty");
return;
}
const isCartCleared = confirm(
"Are you sure you want to clear all items from your shopping cart?"
);
if (isCartCleared) {
this.items = [];
this.total = 0;
productsContainer.innerHTML = "";
totalNumberOfItems.textContent = 0;
cartSubTotal.textContent = 0;
cartTaxes.textContent = 0;
cartTotal.textContent = 0;
}
}
calculateTaxes(amount) {
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
}
calculateTotal() {
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
const tax = this.calculateTaxes(subTotal);
this.total = subTotal + tax;
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
cartTaxes.textContent = `$${tax.toFixed(2)}`;
cartTotal.textContent = `$${this.total.toFixed(2)}`;
return this.total;
}
};
const cart = new ShoppingCart();
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
[...addToCartBtns].forEach(
(btn) => {
btn.addEventListener("click", (event) => {
cart.addItem(Number(event.target.id), products);
totalNumberOfItems.textContent = cart.getCounts();
cart.calculateTotal();
})
}
);
cartBtn.addEventListener("click", () => {
isCartShowing = !isCartShowing;
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
cartContainer.style.display = isCartShowing ? "block" : "none";
});
clearCartBtn.addEventListener("click", cart.clearCart.bind(cart));