What's the best way to add a default action to a Stimulus component?

Viewed 1462

When creating a Stimulus component that should always do the same thing on a certain event (eg. on "hover"), what's the preferred way to set up that action?

I want to write this, for example:

<a data-controller="tooltip" title="something">Show a tooltip on hover</a>

instead of

<a data-controller="tooltip" title="something" data-action="hover->tooltip#showTooltip">Show a tooltip on hover</a>

Including the data-action="hover->tooltip#showTooltip" feels very redundant to me if the only point of the Stimulus component is to show the tooltip on hover.

I'm doing this right now by adding an event listener manually in the initialize() function, but I'm not sure if that's a good idea:

export default class Tooltip extends Controller { 
  initialize(){
    this.element.addEventListener("hover", showTooltip())
  }

  showTooltip(){
    // ...
  }
}
2 Answers

Stimulus doesn't have default event support as far as I know, but adding an event listener by hand works, just don't do it in the initialize() method. Use connect() to add the listener and disconnect() to remove it. I will show an example with the click event, but it should work the same with hover.

Your listener must have the controller as this, otherwise you won't be able to access targets and values. This is why I added the following: this.clickListener = this.confirm.bind(this);. Or you can use an arrow function instead of the bind, like this:

this.clickListener = (event) => this.confirm(event);

Both works the same. So here is the full example:

import { Controller } from 'stimulus';

export default class extends Controller {
    connect() {
        this.clickListener = this.confirm.bind(this);
        this.element.addEventListener('click', this.clickListener);
    }

    disconnect() {
        this.element.removeEventListener('click', this.clickListener);
    }

    confirm(event) {
        event.preventDefault();
        console.log(event);
    }
}

That is a bit redundant, but you don't need the initialize method here. I think the correct action for Stimulus is mouseover. That's probably why hover isn't working the way it should.

And be careful about your case for the method in the data-action. I tend to make all methods that are called in data-actions to be single word, lower case (ie. showtooltip). That way I don't have to remember the weird naming convention.

More importantly, this is not a case where Stimulus is really at is best. Most CSS frameworks have a tooltip tie-in that uses a bit of jQuery or vanilla JS. Stimulus is really great for modular JS. For instance, I use it to build charts with HighCharts. I can set dataset values like "url", "chartTitle", "yAxisTitle", call them in my stimulus controller and use the same controller for every line chart on my site. GoRails has a video on how to make a Cocoon clone with Stimulus. You're using the tweezers for a splinter from the 25-tool Swiss Army knife. You can do it; you just won't really see the benefits of having the pocket knife.

Related