OOP "Classes" and DOM manipulation with JavaScript, undefined element

86 Views Asked by At

This is my first personal project using JavaScript to make a website dynamic. I don't feel utterly lost, but after a few days I will take a knee at being "stuck". I have a grid container containing 6 items which I would like to attach a "click" eventListener to. Essentially I am using Classes and Constructors to organize my code, and my problem likely lies in inadequate familiarity with how to compose the code properly.

// these are the `grid items`
function mapContainers() {
    let values = ["1", "2", "3", "4", "5", "6"];
    let gridItems = values.map((element) => {
        return document.querySelector(`.item${element}`);
    });
    return gridItems;
}

// this is my GridButton Class
class GridButton {
    constructor(button, direction) {
        this.button = button;
        this.direction = direction;
    }

    // Getter
    get whenClicked() {
        return this.button.addEventListener("click", popUp(`${this.direction}`));
    }
    // Method
    popUp(direction) {
        gridContainer.style.zIndex = "-1";
        gridContainer.style.opacity = "0.2";
        dogBone.style.display = "block";
        dogBone.animate(
            {
                transform: "scale(0, 0)",
                transformOrigin: `${this.direction}`
            },
            {
                transform: "scale(1, 1)"
            },
            {
                duration: 400,
                iterations: 1
            }
        );
    }
}

// this is my init()
function init() {
    // Call functions here
    const gridItems = mapContainers();
    const dogWalking = new GridButton(gridItems[0], "top left");
    const dayCare = new GridButton(gridItems[1], "top right");
    const boarding = new GridButton(gridItems[2], "left");
    const bath = new GridButton(gridItems[3], "right");
    const parties = new GridButton(gridItems[4], "bottom left");
    const petWasteRemoval = new GridButton(gridItems[2], "left");
    dogWalking.whenClicked();
    dayCare.whenClicked();
    boarding.whenClicked();
    bath.whenClicked();
    parties.whenClicked();
    petWasteRemoval.whenClicked();
}

// variously defined variables:
const gridContainer = document.querySelector("services_grid_container");
const serviceElaboration = document.querySelector("service_elaboration");
const serviceElaborationText = document.querySelector("service_elaboration_text");
const dogBone = document.querySelector("dog-bone");
const dogBoneText = document.querySelector("dog-bonetext");

// running the init()
document.addEventListener('DOMContentLoaded', init);

for some reason, the console logs an error:

script.js:19 Uncaught ReferenceError: popUp is not defined
    at get whenClicked [as whenClicked] (script.js:19:28)
    at HTMLDocument.init (script.js:51:16)
get whenClicked @ script.js:19
init @ script.js:51

I'm not sure why it is saying popUp is not defined. I do not mean to be airing out my dirty laundry, I'm just trying to understand! I'll keep trying to understand this in the meantime, but thank you for anyone who considers helping.

I tried consulting Chat GPT, and that didn't solve the problem. Chat GPT suggested adding the eventListener to the constructor, but I couldn't figure that out beyond its code which yielded the same error. I've contemplated integrating popUp into the constructor, but that seems like a dead-end. Finally I am utilizing stack overflow.

1

There are 1 best solutions below

0
Kokodoko On
  • The popup method wasn't found because you didn't use this, and you lost the scope to your class instance, you can fix it with an arrow function.
  • You don't need to pass the direction to the popup method since we are inside a class instance, and the direction is a property.
  • You can add the eventListener right away and you don't have to return it.
  • You have to ask yourself if all the popup code has to be in each class instance, since the popup is not really a part of the grid item. It's also not so common to use global variables (container and dog bone) in a OOP class.
    // these are the `grid items`
    function mapContainers() {
      let values = ["1", "2", "3", "4", "5", "6"];
      let gridItems = values.map((element) => {
        return document.querySelector(`.item${element}`);
      });
      return gridItems;
    }
    
    // this is my GridButton Class
    class GridButton {
      constructor(button, direction) {
        this.button = button;
        this.direction = direction;
        this.button.addEventListener("click", () => this.popUp());
      }
    
      popUp() {
        console.log(`popup code for direction: ${this.direction}`)
    
        gridContainer.style.zIndex = "-1";
        gridContainer.style.opacity = "0.2";
        dogBone.style.display = "block";
        dogBone.animate({
          transform: "scale(0, 0)",
          transformOrigin: this.direction
        }, {
          transform: "scale(1, 1)"
        }, {
          duration: 400,
          iterations: 1
        });
      }
    }
    
    // create grid items
    function init() {
      const gridItems = mapContainers();
      const dogWalking = new GridButton(gridItems[0], "top left");
      const dayCare = new GridButton(gridItems[1], "top right");
      const boarding = new GridButton(gridItems[2], "left");
      const bath = new GridButton(gridItems[3], "right");
      const parties = new GridButton(gridItems[4], "bottom left");
      const petWasteRemoval = new GridButton(gridItems[5], "left");
    }
    
    const gridContainer = document.querySelector(".services_grid_container");
    const dogBone = document.querySelector(".dog-bone");
    init();

As a side note, if you want to learn more about using OOP classes with DOM manipulation, you can look at web components / custom elements: https://developer.mozilla.org/en-US/docs/Web/API/Web_components