1

I am executing the function delayFilter() on keyup of an input box. I want to delay 1 second after the user stops typing and run the function filterProducts(). However, when executing filterProducts() inside of the setTimeout I get the console error "this.filterProducts is not a function". This function gets called fine when outside of the setTimeout. Why is this error being thrown?

  delayFilter() {
    let timeout = null;
    clearTimeout(timeout);

    timeout = setTimeout(function() {
      this.filterProducts();
    }, 1000);
  }

  filterProducts() {
    //do stuff
  }
noclist
  • 1,659
  • 2
  • 25
  • 66
  • This is a context issue. Not an issue with setTimeout. – devd Sep 02 '20 at 16:13
  • 1
    Using `clearTimeout` directly after overwriting your refernce to the timeout (`timeout = null`) isn't going to have the desired effect. – DBS Sep 02 '20 at 16:13
  • Does this answer your question? [Pass correct "this" context to setTimeout callback?](https://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback) – tevemadar Sep 02 '20 at 16:17

2 Answers2

3

That is because these, this inside the callback, does not refer to the object outside.

Try this:

delayFilter() {
    let timeout = null;
    clearTimeout(timeout);
    let self = this;
    timeout = setTimeout(function() {
      self.filterProducts();
    }, 1000);
  }

  filterProducts() {
    //do stuff
  }

You can also try the arrow function. The reason can be seen here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords.

delayFilter() {
    let timeout = null;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      this.filterProducts();
    }, 1000);
  }

  filterProducts() {
    //do stuff
  }
Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
1

You need to bind the scope of the function in the setTimeout callback. the easiest way is to use arrow functions, if your platform supports it.

timeout = setTimeout(() => this.filterProducts(), 1000);

you can also save the scope in a variable.

var self = this;
timeout = setTimeout(funciton() { self.filterProducts() }, 1000);

Alternatively you can manually bind it. This is useful if you want to pass the function around.

timeout = setTimeout(function() {...}.bind(this), 1000);
Brenden
  • 1,947
  • 1
  • 12
  • 10