Multiple controller for one element? #198
-
As I understand, Catalyst is heavily inspired by Stimulus. Using Stimulus it's possible to attach multiple controllers [1] to the same element like this: <div data-controller="clipboard list-item"></div> Is this possible to do with Catalyst? Or is that impossible since there seem to be more of a 1-to-1 mapping of a Catalyst controller and a custom element. [1] https://stimulus.hotwired.dev/reference/controllers#multiple-controllers |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Thanks for the question @jacob-carlborg! The short answer is no - not multiple per element; but the longer and probably more appropriate answer is: yes but with a bunch of different ways, depending on what fits. You're right, Catalyst is heavily inspired by Stimulus, and their controllers sort of act like "mixins", applying a set of behaviours one-after-the-other. Catalyst leans heavily on Web Components in fact we want to ensure that Catalyst "is just web components". Web Components allow for composition, but there's various patterns depending on what fits. You can use an array of class based patterns: inheritance chains, abstract classes, mixins. You can also compose with html-elements, wrapping one inside the other. We use both patterns at GitHub depending on the use case. To take Stimulus' example they specify a <list-item>
<clipboard-controller>
...
</clipboard-controller>
</list-item> This works well because you can control the order and scope, eg one controller per item or one for all items. We use this style a lot at GitHub as it's easy to reason about. However there's a few other methods in JS you can use. Sometimes if the inheritance chain makes sense, we can express it as a superclass: class ClipboardController extends HTMLElement {
...
}
@controller
class ListItem extends ClipboardController {
...
} We rarely use superclasses at GitHub. Even rarer but also possible is to express it as a mixin: @controller
class ListItem extends clipboardController(HTMLElement) {
...
} Or a decorator, which is a pattern we prefer: @controller
@clipboardController
class ListItem extends HTMLElement {
...
} Or something we often do is literally just have a function that we call in the connectedCallback: @controller
class ListItem extends HTMLElement {
connectedCallback() {
clipboardController(this)
}
} I think the above patterns give you a ton of flexibility, but it can be a bit confusing (maybe even daunting) figuring out which ones to use. All are totally viable, but if you're looking for a recommendation for one, I'd recommend composing elements in HTML, and resorting to functions that you can call in a connectedCallback if the HTML option doesn't feel like the best fit. |
Beta Was this translation helpful? Give feedback.
Thanks for the question @jacob-carlborg!
The short answer is no - not multiple per element; but the longer and probably more appropriate answer is: yes but with a bunch of different ways, depending on what fits.
You're right, Catalyst is heavily inspired by Stimulus, and their controllers sort of act like "mixins", applying a set of behaviours one-after-the-other. Catalyst leans heavily on Web Components in fact we want to ensure that Catalyst "is just web components".
Web Components allow for composition, but there's various patterns depending on what fits. You can use an array of class based patterns: inheritance chains, abstract classes, mixins. You can also compose with html-elements,…