Stimulus Discourse

_.throttle inside a controller


#1

Anyone know how to use _.throttle inside a controller? I’ve tried it, but it tells me the method I’m trying to throttle isn’t a function. It kind of feels like there should be some way to throttle baked into the event handling of Stimulus. If I’m using a keyup event, I want to have a little delay when firing the POST off to the server.


#2

You can throttle an action method in initialize:

import { Controller } from "stimulus"

export default class extends Controller {
  initialize() {
    this.pressKey = _.throttle(this.pressKey, 100)
  }

  pressKey(event) {
    console.log(`Pressed key: ${event.char}`)
  }
}

Alternatively, define a function decorator that does this for you:

import { Controller } from "stimulus"

function throttle(wait) {
  return function (target, name, descriptor) {
    const { value } = descriptor

    if (typeof value === "function") {
      descriptor.value = _.throttle(value, wait)
    }

    return descriptor
  }
}

export default class extends Controller {
  @throttle(100)
  pressKey(event) {
    console.log(`Pressed key: ${event.char}`)
  }
}

You can move the throttle decorator to a different file and import it where you need it. (Note that to take the decorator approach, you’ll need to install a transpiler plugin such as the transform-decorators plugin for Babel.)


#3

Excellent, I used the initializer approach. Thanks for the info!


#4

I’m having an issue along the same thread. I’m trying to run this:

initialize() {
  window.addEventListener('scroll', _.throttle(this.isInView, 500))
}

isInView() {
  console.log(this.element);
}

However this.element is not available in my function isInView() for some reason. It returns ‘undefined’ in the console. Can’t figure out why. Thanks for the help in advance!


#5

I’m guessing that this is referring to the lodash function and not your stimulus class. Try adding this to your controller near the top of the file:

import { Controller } from 'stimulus'
let throttle = require('lodash/throttle');

Then call:
throttle(this.isInView, 500) instead of _.throttle(this.isInView, 500).

initialize() {
  window.addEventListener('scroll', throttle(this.isInView, 500))
}

isInView() {
  console.log(this.element);
}