javascripthtmlclass

Bind object instance to the "this" keyword in addEventListener function


I have a class for an editor that attaches menus and events when enabled. I want to capture keyboard events related to this editor, which trigger functions within the object instance when pressed. The following works as intended, making the ' key toggle an editor element:

var edit = null;

class editor {
    constructor() {
        this.element = document.createElement("div");

        addEventListener("keydown", function(event) {
            if(event.key == "`") {
                edit.toggle();
            }
        });
    }

    toggle() {
        if(root.contains(this.element)) {
            document.body.removeChild(this.element);
        } else {
            document.body.appendChild(this.element);
        }
    }
}

edit = new editor();

The problem is I can't make addEventListener call the this.toggle function of the object: I tried using bind but nothing I did works, I can't make the event listener carry the object reference when using the this keyword. As such I store my object in a global var and have the object's internal functions call itself through that var, which feels like a messy and wrong way to do it, especially if I decide to use multiple instances in which case the reference would need to be unique. Here's a version that gets close to what I'm trying to achieve but won't work:

class editor {
    constructor() {
        this.element = document.createElement("div");

        addEventListener("keydown", function(event) {
            if(event.key == "`") {
                this.toggle();
            }
        }).bind(this);
    }

    toggle() {
        if(root.contains(this.element)) {
            document.body.removeChild(this.element);
        } else {
            document.body.appendChild(this.element);
        }
    }
}

new editor();

Solution

  • You're not binding the callback function (which is where you want to use this), you're binding the addEventListener function itself (and discarding the result).

    Either bind the callback:

    addEventListener("keydown", function(event) {
      if(event.key == "`") {
        this.toggle();
      }
    }.bind(this));
    

    Or use arrow functions:

    addEventListener("keydown", event => {
      if(event.key == "`") {
        this.toggle();
      }
    });