0

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.

d709859
  • 3
  • 1
  • 1
    What is `this.addToCartHandler = this.addToCartHandler;` supposed to do? `this.addToCartHandler(posButton);` in a static method means that you also have a static `addToCartHandler`, but you clearly don’t. Why not simply make `addToCartHandler` static? – Sebastian Simon Dec 22 '22 at 11:59
  • Hi Sebastian, thank you very much for coming back to me. I have made that change and it is now working correctly - thank you for helping. For my understanding, why was the error showing as I thought i had defined the function in the constructor through this.addToCartHandler = this.addToCartHandler? Should this only be used when I am creating multiple instances of the object? – d709859 Dec 22 '22 at 16:52
  • `this.addToCartHandler = this.addToCartHandler` is completely redundant. It does nothing useful. `this` is the instance in the constructor and in non-static class elements. In _static_ class elements, `this` refers to the class itself, not the instance. – Sebastian Simon Dec 22 '22 at 21:38

0 Answers0