Home > Enterprise >  eventlistener once property prevents other eventlistener issue
eventlistener once property prevents other eventlistener issue

Time:09-27

constructor() {
    document.addEventListener("keyup", this.keyStart.bind(this), {once:true});
    document.addEventListener("keydown", this.keySpaceHandler.bind(this));
}
keySpaceHandler(e) {
    if (e.keyCode === 32 && missile_count > 0) {
        ...
    }
}

keyStart(e) {
    if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
        isGameStart = true;
        if (isGameStart === true) {
            ...
        }
    }
}

I want keyStart to listen to the event only once so it does not get called every single time user uses arrow key but only the first time to start the game. The problem occurs when user presses space key then arrowkey. Because I set keyStart property to once:true, it does not listen to any event if any other key is pressed before arrow key. Is there a way to solve this problem so that even if user presses any other keys before arrow key, once they press arrow key, keyStart is called and game starts as expected? Thank you in advance!

CodePudding user response:

Code it so it checks a boolean inside of the event so you ignore the function from being run again and again.

keyStart(e) {
  if (this.isGameStart) return true;
  if (["ArrowLeft", "ArrowRight"].includes(e.key)) {
    this.isGameStart = true;
  }
}

If you do not want to have the event being triggered you can remove the event by storing the function reference and calling removeEventListener

constructor() {
  this.startListenerFunc = this.keyStart.bind(this);
  // this.startListenerFunc = e => this.keyStart(e);
  document.addEventListener("keyup", this.startListenerFunc);
}

keyStart(e) {
  if (["ArrowLeft", "ArrowRight"].includes(e.key)) {
    document.removeEventListener("keyup", this.startListenerFunc);
    this.isGameStart = true;
  }
}

CodePudding user response:

There are a few informal proposals every now and then to add a "condition" to once for this exact case. But nothing I know that won the required implementers interest yet. For the time being, the most ergonomic solution is to use an AbortController instead that you can pass in the signal option of addEventListener().

const missile_count = 32;
class Stuff {
  constructor() {
    const controller = new AbortController();
    document.addEventListener("keyup", this.keyStart.bind(this, controller), {
      signal: controller.signal
    });
    document.addEventListener("keydown", this.keySpaceHandler.bind(this));
  }

  keySpaceHandler(e) {
    if (e.keyCode === 32 && missile_count > 0) {
      // ...
    }
  }

  keyStart(controller, e) {
    if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
      controller.abort(); // removes the event handler
      console.log("starting game");
    } else {
      console.log("ignoring other key");
    }
  }
}
const stuff = new Stuff();
Press ArrowLeft or ArrowRight.

  • Related