0

I cannot make the timer to call my class method. This works fine:

MyInput = class {
 constructor(params) {
  let input = params.input;
  input.addEventListener('focus', this.setTimer);
 }

 setTimer() {
  this.timer = window.setInterval(() => {
   console.log('yay');
  }, 300);
 }
};

but this:

MyInput = class {
 constructor(params) {
  let input = params.input;
  input.addEventListener('focus', this.setTimer);
 }

 setTimer() {
  this.timer = window.setInterval(this.lookupOptions, 300);
 }

 lookupOptions() {
  console.log('yay');
 }
};

doesn't call the lookupOptions method but instead, my developer tools in the browser stops debugger every 300ms (checked with different values - always in synch with the timer). After a while, it opens some strange file VM[number] with different numbers. I have no idea why it doesn't work. When I used timer outside the class in the same way it worked fine it seems like some problem with calling the class method but I cannot figure out what the problem might be. Could you please help?

Lioness100
  • 8,260
  • 6
  • 18
  • 49
Malvinka
  • 1,185
  • 1
  • 15
  • 36
  • 1
    window.setInterval(this.lookupOptions.bind(this), 300); – enno.void Oct 08 '20 at 13:38
  • @enno.void Uncaught TypeError: Cannot read property 'bind' of undefined – Malvinka Oct 08 '20 at 13:43
  • Use arrow functions to keep the instance as context: `input.addEventListener("focus", e => this.setTimer(e));` and `this.timer = window.setInterval(() => this.lookupOptions(), 300);` –  Oct 08 '20 at 13:45
  • Does this answer your question? [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) –  Oct 08 '20 at 13:49

1 Answers1

2

When setInterval calls the function it changes the context of this to the scope of the setInterval, which would be the window object.

Scope the callback in setInterval by wrapping it with an arrow function expression. This prevents the scope from being changed.

MyInput = class {
    constructor(params) {
        let input = params.input;
        input.addEventListener("focus", () => {
            this.setTimer();
        });
    }

    setTimer() {
        this.timer = window.setInterval(() => {
            this.lookupOptions();
        }, 300);
    }
  
    lookupOptions() {
         console.log("yay");
    }
}

Or use the .bind() method, that is present on each function object to manually set the scope for this.

MyInput = class {
    constructor(params) {
        let input = params.input;
        const boundSetTimer = this.setTimer.bind(this)
        input.addEventListener("focus", boundSetTimer);
    }

    setTimer() {
        const boundLookupOptions = this.lookupOptions.bind(this)
        this.timer = window.setInterval(boundLookupOptions, 300);
    }
  
    lookupOptions() {
         console.log("yay");
    }
}

Or use the experimental public fields, which do somewhat the same as arrow function expressions, but as a method of an object.

MyInput = class {
    constructor(params) {
        let input = params.input;
        input.addEventListener("focus", this.setTimer);
    }

    setTimer = () => {
        this.timer = window.setInterval(this.lookupOptions, 300);
    }
  
    lookupOptions = () => {
         console.log("yay");
    }
}
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32
  • Unfortunately bind approach gives me "ncaught TypeError: Cannot read property 'bind' of undefined at HTMLInputElement.setTimer (clinput.js:44)" error while arrow method "is not a function" error. – Malvinka Oct 08 '20 at 13:46
  • You also need `this.setTimer.bind(this)` –  Oct 08 '20 at 13:46
  • Why then `input.addEventListener("focus", this.setTimer)` in construction works without binding? – Malvinka Oct 08 '20 at 13:46
  • Because in the constructor, `this` references the instance, so `this.setTimer` correctly points to the method. Without the binding though, `this` *inside* `setTimer` points to the input instead. –  Oct 08 '20 at 13:48
  • @ChrisG thank you so much for the explanation! Now I understand how it works. And it is working! – Malvinka Oct 08 '20 at 13:56