I am trying to create a page that generates a list of products by calling an API and then gives the user the ability to add a product to the cart total amount. I am coming across an issue where I can't seem to get the addToCartHandler working in the APISection class. I didn't declare it in the constructor as the posButton and negButton haven't been created on page load. Would someone be able to share what I am doing wrong in the below code please? It could be something to do with my use of this but I haven't been able to work out what the issue is. Once I connect the handler, I want to generate an instance of the Cart class and have the positive/negative buttons for each product change the cart total amount.
Currently getting the below error:
script.js:91 Uncaught (in promise) TypeError: this.addToCartHandler is not a function
Any help would be greatly appreciated!
Javascript
class ScrollFeature {
constructor() {
this.showOnPx = 100;
this.elem = document.querySelector(".back-to-top");
this.pageProgessBar = document.querySelector(".progress-bar");
this.scrollContainer();
this.elem.addEventListener("click", this.goesToTop);
document.addEventListener("scroll", () => {
const scrolledPercentage =
(this.scrollContainer().scrollTop /
(this.scrollContainer().scrollHeight -
this.scrollContainer().clientHeight)) *
100;
this.pageProgessBar.style.width = `${scrolledPercentage}%`;
if (this.scrollContainer().scrollTop > this.showOnPx) {
this.elem.classList.remove("hidden");
} else {
this.elem.classList.add("hidden");
}
});
}
scrollContainer() {
return document.documentElement || document.body;
}
goesToTop() {
document.body.scrollIntoView({ behaviour: "smooth" });
}
}
class Cart {
constructor() {
this.cartTotal = 0;
const totalElement = document.getElementById("total");
totalElement.textContent = this.cartTotal;
}
}
class APIContainer {
constructor() {
this.connectAPICaller();
this.addToCartHandler = this.addToCartHandler;
;
}
connectAPICaller() {
this.button = document.querySelector(".btn-primary");
this.button.addEventListener("click", this.callApi);
}
static createElement(type, className, product, id, innerHTML) {
const element = document.createElement(type);
element.classList.add(className);
element.id = id;
element.textContent = product;
if (innerHTML) {
element.innerHTML = innerHTML;
}
return element;
}
static renderItem(product) {
const apiSection = document.querySelector(".api-section");
const listItem = APIContainer.createElement(
"li",
"New-section",
product,
""
);
apiSection.appendChild(listItem);
const posButton = APIContainer.createElement(
"button",
"cartButtonPositive",
" ",
"posId",
`<i class="fa-solid fa-plus"></i>`
);
const negButton = APIContainer.createElement(
"button",
"cartButtonNegative",
"",
"negId",
`<i class="fa-solid fa-minus"></i>`
);
posButton.style.textAlign;
negButton.style.textAlign;
listItem.insertAdjacentElement("beforeend", posButton);
listItem.insertAdjacentElement("beforeend", negButton);
this.addToCartHandler(posButton);
}
addToCartHandler(posButton) {
if (posButton) {
posButton.addEventListener("click", console.log(posButton));
}
const cart = new Cart();
console.log(cart);
// const addCart = document.getElementById("posId");
// console.log(addCart);
// addCart.addEventListener("click", () => {
// console.log(this.cart.cartTotal);
//add a cart object and increase amount
}
async callApi() {
const response = await fetch("https://dummyjson.com/products");
const number = Math.floor(Math.random() * 30);
const data = await response.json();
const product = data.products[number].title;
APIContainer.renderItem(product);
}
}
class ToDo {
constructor() {
this.addHandler = (e) => {
if (e.target.classList.contains("active")) {
e.target.classList.remove("active");
} else {
e.target.classList.add("active");
}
};
this.removeHandler = (e) => {
e.target.classList.remove("active");
};
this.connectToDoList();
}
connectToDoList() {
const listItems = document.getElementsByClassName("list-group-item");
console.log(listItems);
const listItemArray = Array.from(listItems);
for (const el of listItemArray) {
if (!el.classList.contains("active")) {
el.addEventListener("click", this.addHandler);
} else {
el.addEventListener("click", this.removeHandler);
}
}
}
}
class App {
static init() {
new ScrollFeature();
new Cart();
new APIContainer();
new ToDo();
}
}
App.init();
`
HTML
`
<!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" />
<script src="script.js" defer></script>
<script
src="https://kit.fontawesome.com/70618170b9.js"
crossorigin="anonymous"
></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
crossorigin="anonymous"
rel="stylesheet"
/>
<link href="app.css" rel="stylesheet" />
<title>Document</title>
</head>
<body>
<section class="topContainer">
<div class="progress-bar"></div>
<button class="back-to-top hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-4 back-to-top-icon"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18"
/>
Button
</svg>
</button>
<div class="api-section">
<h2>Randomly select an item to buy:</h2>
<button id="submitButton" type="submit" class="btn btn-primary">
Select product
</button>
</div>
<div class="cart">
<div class="cartTotal"><span id="total">Total</span></div>
<i class="fa-solid fa-cart-shopping fa-10x"></i>
</div>
</section>
<section>
<ul class="list-group">
<header>To-do List</header>
<li class="list-group-item">Point 1</li>
<li class="list-group-item">Point 2</li>
<li class="list-group-item">Point 3</li>
</ul>
</section>
</body>
</html>
`
Trying to connect handler to then generate a cart class and have the handler increase/decrease cart total amount.