0

I'm trying to make a JS puzzle game (image drag and drop). I'm trying to assign the tiles (images) of the puzzle to the event listeners, but then the populate function doesn't work and won't populate the board. When removed it prints the images with no problem. I guess a workaround would be to make an assignEvents() function after the board has been populated. Every help would be much appreciated.

class PuzzleGame extends Game {
  constructor() {
    super();
    this.rows = 3;
    this.columns = 3;
    //current clicked image, other the one we swap with
    this.currTile;
    this.otherTile;
    this.turns = 0;
    this.imageOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    this.randomOrder = [];
  }
  populateBoard() {
    for (let r = 0; r < this.rows; r++) {
      for (let c = 0; c < this.columns; c++) {
        let tile = document.createElement("img");
        tile.id = r.toString() + "-" + c.toString();
        tile.src = "./images/" + this.randomOrder.shift() + ".png";
        // drag functions
        tile.addEventListener("dragstart", dragStart);
        tile.addEventListener("dragover", dragOver);
        tile.addEventListener("dragenter", dragEnter);
        tile.addEventListener("dragleave", dragLeave);
        tile.addEventListener("drop", dragDrop);
        tile.addEventListener("dragend", dragEnd);

        document.getElementById("board").append(tile);
      }
    }
  }
  _randomizeOrder() {
    if (!this.imageOrder) return undefined;
    this.randomOrder = this.imageOrder.sort(function () {
      return Math.random() - 0.5;
    });
    return this.randomOrder;
  }
  puzzleStart() {
    this._randomizeOrder();
    this.populateBoard();
  }
  dragStart() {
    this.currTile = this; //image being dragged
  }
  dragOver(e) {
    e.preventDefault();
  }
  dragEnter(e) {
    e.preventDefault();
  }
  dragLeave() {}
  dragDrop() {
    this.otherTile = this; //image tile being dropped on
  }
  dragEnd() {
    let currImg = this.currTile.src;
    let otherImg = this.otherTile.src;
    this.currTile.src = otherImg;
    this.otherTile.src = currImg;
  }
}

I tried to assign the addeventlisteners to the tiles of the game while populating the board. In each iteration of the loop I tried to assign the events expecting to populate it AND at the same time painting the image on the board.

DreamBold
  • 2,727
  • 1
  • 9
  • 24
  • Your event handlers are not bound to an instance of `PuzzleGame`. So referring to `this` in the handler will either be `undefined` or point to the global context. Try changing it to: `tile.addEventListener("dragstart", this.dragStart.bind(this));` – Abrar Hossain Dec 07 '22 at 15:42
  • Two issues: 1. When doing web development, it's important to look in the browser console for error messages. In this case, you'll be getting a `ReferenceError` saying that `dragStart` is not defined. Using `this.` when accessing object members is not optional in JavaScript classes. You need `tile.addEventListener("dragstart", this.dragStart);` and similar. 2. If you want to use `this` within `dragStart` and such to refer to your instance instead of the HTML element, you need to use `bind` or similar. See the answers to the two linked questions for details on both. – T.J. Crowder Dec 07 '22 at 15:43
  • 1
    @AbrarHossain - No, `this` inside the handler will be a reference to the element the handler was attached to, not `undefined` or the global object (which isn't a "context'). But yes, it won't be the class instance. :-) – T.J. Crowder Dec 07 '22 at 15:43
  • Exactly that, i was missing the "this." before the methods, as I am inside of a class. Thanks a lot. Really long hours made me not realize. Sorry for the obvious question. – Jorge Mendez Dec 07 '22 at 15:47

0 Answers0