Advice Request: Communication between Stimulus controllers

So, first of all, I’m relatively new to doing much front-end besides the odd sprinkle of jQuery here and there. That said, I’ve really been finding Stimulus useful. I’ve built up a handful of reusable components for my application and enjoy how everything is nice and encapsulated.

I’ve got one controller that I call Treepicker. It’s a wrapper around a plain-JS selectbox, configured and with some back-end help to search, display, and select models that use ancestry or awesome_nested_set or whatever.

Now I’d like to have a form where inputs are displayed or hidden depending on which option is selected in the Treepicker controller.

The form is a multi-row form with an arbitrary number of rows. Each row has one Treepicker and a bunch of other fields. Add and remove are already working correctly. I already have CSS classes for the row set up so that the correct fields are hidden or displayed depending on which CSS class is applied to the row.

So the “obvious” solution to me is to make a new Stimulus controller that would attach to each row. Each one would have as its target the Treepicker controller and watch it for changes to change its CSS class.

The problem is I don’t know the “right” way to monitor the Treepicker for changes and then to ask it for its current value. I suspect that there’s something I should do about emitting an event (in the Treepicker controller?) and subscribing to it (in the Row controller?).

I’m sure I could bung something together, but as I’m working with something so new to me, I’m afraid of doing something that works but is incredibly brittle, so I thought I’d ask in here to see what “the right way” is.

Thanks in advance!

To answer my own question, I ended up doing something like this:

In the Treepicker controller:

    valueChanged(value): void {
        const item = this.tomSelect.options[value];
        const event = new CustomEvent("treepicker-value-selected", {bubbles: true, detail: item});
        this.element.dispatchEvent(event);
    }

And in the Row controller:

    initialize(): void {
        this.treepickerTarget.addEventListener('treepicker-value-selected', this.aoeu)
    }

    aoeu(): void {
        console.log("hello")
    }

It works for now; if anyone can spot a glaringly stupid thing I’ve done, please let me know!

1 Like

Thanks for posting the answer, I was wondering how to do the same thing.

Hey there - the reference docs has a (somewhat hidden) section about this : Stimulus Reference

It’s basically the same thing you’re doing - just adding the syntactic sugar thing of making it easy to register the listener and namespacing the event(s).

/Chriztian

1 Like

I ended up finding that, but I think the version of Stimulus that I’m using is too old to have this.dispatch(). I’ll look into upgrading later when I’m not 4 days past a deadline :slight_smile: