The more generic you can make your Stimulus controllers, the better.
We'll explore how to put more control in the hands of the consumer of your Stimulus controller by providing a data attribute configure a controller (and a fallback, in case an attribute isn't provided).
We'll also look at how we can make your code "open for extension, but closed for modification" (part of SOLID). We'll refactor a ternary operator to use an object literal lookup. This will help make a method "do one thing" (bordering on "single responsibility principle", the S in SOLID).
Damon Bauer: [0:00] One way to make your controllers more reusable and more generic and extendable is to provide options via data attributes. In this case, one of the things we're doing a lot is hiding and showing elements using the is-hidden class.
[0:15] One of the things we can do in our controller is add an attribute that allows the user to set what class they want to add or remove to hide or show elements.
[0:29] I've added a data attribute and I've prefixed my option with the name of our controller, collection-filter. I've added my option at the end here, hidden-class. Let's go to our controller and we'll add a connect() method.
[0:42] The connect method is called by stimulus, any time this controller is connected to the DOM. Most typically, this would be when a page is loaded for the first time. It will also be called any time the controller dominoes are injected into the page.
[0:59] Within the connect method, I'll assign a new variable. Stimulus gives us some nice hooks to get data attributes. We can call this.data.get and then we get that camel case version of our option that we set. I set hidden-class here.
[1:19] To access that in our JavaScript, we do the camel case version and then providing a fallback to say if a user doesn't set that option in their controller, we'll default that to is-hidden. Now, all I have to do is replace the usages in this file.
[1:36] One final thing I want to do is clean up this ternary. If there are another case, we'd have to either add a new ternary or add a bigger if statement or add a switch statement. None of those feel very clean. Rather than those options, I'm going to opt for looking up in option using the object literal pattern.
[1:58] The way this works is we define an object. Within this object, one of the keys will be date. We're going to execute a function. This function will take input and this function is going to execute our dayjs function here. I'll paste that in and rather than this user input variable, we'll take that input there. That handles this side of the ternary. We need to handle this side of the ternary which is the default case.
[2:34] Now, let's replace our ternary. First, we'll get our object then we'll look up the key that corresponds to the user's chosen option. If they've chosen an option that's not in our input map, meaning it needs to fall to the default case, we'll look that up.
[2:58] We need to wrap this in parentheses to make sure that we execute that part first. We need to get the function that corresponds to the correct key in each one of these cases. If we use our select date, we need to make sure we grab this function.
[3:14] Otherwise, we need to make sure we grab the default function by wrapping this or operation in parentheses and make sure we have the correct reference to the correct function. With that reference, we can then execute it and pass in the USER_INPUT.
[3:31] The nice thing about this is if we added another input to our HTML, the only thing that we'll have to change is in this map. Now, nothing else about our controller has to change and the between is very easy to test that or to add options and see exactly what each option is supposed to do.