Stimulate your Rails App Using Stimulus!!
Tired of JQuery/Plain Js? Try Stimulus
Over the years, in order to include the dynamicity that Javascript brings into every application in terms of DOM manipulation, many ROR developers looked to JQuery. In 2018, DHH, the creator of Ruby on Rails, published a new JavaScript framework called Stimulus
and since then, one of the most popular descriptions of Stimulus
has been that it is “the JavaScript framework with modest ambitions”.
As stated in its documentation, Stimulus was designed to enhance static or server-rendered HTML — the “HTML you already have”. It is a rare occurrence to read a slice of HTML that has an external JavaScript file for its event handlers and tell exactly what the handlers would do at each point; on the other hand, with Stimulus, you can read a slice of HTML and tell exactly what is going on.
It works with a few concepts, namely:
- Controllers
- Actions
- Targets
Looking at that list, what do you see? Separation of concerns, eh? I love, love it 😃! We’ll cover how these work together to add beauty to your Rails app while keeping your code less verbose, clean, and more readable. Enough of that talk, let’s write some code.
INSTALL STIMULUS
My app currently uses Rails 6.1
, and as a result, webpacker and yarn are already installed. To install Stimulus, we use the following command;
rails webpacker:install:stimulus
As seen in the image above, some appending is done to application.js
to import the controllers
, and new files and folders are created within the javascript folder. One thing to note is that the controllers
folder created here is not related to the traditional controllers
folder created in the Rails app
folder; they only bear the same name.
INITIAL TEMPLATE
Let’s explore the stuff that came with our installation. In our app/javascript/controllers/hello_controller.js
file, we’ll find some commented-out HTML. Let’s move that HTML to our html.erb
file. This can be whatever file you choose in your app to display on the server.
On server reload, this should be displayed.
What in heaven’s name just happened 😕? Let’s break it down.
- The Controller: A controller file named
hello_controller.js
exists in ourcontrollers
folder.
Here, a class is created and exported. Within this class, a static array is defined which contains the targets of this controller. As seen, we have an output
target defined as "output"
; this means that we can henceforth refer to this target as this.outputTarget.
If we include another target "showName"
, we would refer to it within the class as this.showNameTarget
; a good practice would be to name targets according to what they should or do display, in order to aid code readability. Within this class also lies a connect
function which is invoked on the connection of the controller in question to the DOM; this function assigns the text content of Hello, Stimulus
to the output target.
- The HTML: Within the HTML file, we have an encapsulating
div
which possesses adata-controller
attribute. This is where the name of the controller to be used is specified. As seen, the value of this attribute is"hello"
, connecting thediv
to thehello-controller
. Also, recall that we have an output target within the controller that should display a certain text, this target also has to be specified within thediv
, using thedata-target
attribute. In ourhtml.erb
file, its value is"hello.output"
, meaning the output target of the hello controller. It is important to note that in future versions of Stimulus, thedata-target
attribute will be deprecated and we are urged to replace it withdata-controllerName-target = “targetName"
.
And just like that, we got Stimulus working 💃. Not so fast though, let’s add some code of our own 😄.
HTML
It all starts with HTML. What can we build? Let’s build a simple app, within which we determine by how much we would like to reduce or increase a number.
As seen above, I have created a div
and added a data-controller
attribute to connect it to a certain controller named calculate
. I make it a habit to write my Html before creating my controller; this helps me keep my code readable, as I can ensure no one needs to see my controller to understand what is going on. Within this div
, I have added the following:
- A
data-target
attribute to theh3
tag that refers to the current value of the calculation. This is where the computed value will be shown. - A
data-target
attribute to theinput
tag that refers to the addend value. This is the value that we would type in for addition or subtraction from the current value. - A
data-action
attribute to two buttons that carry out theadd
andsubtract
actions.
Yes, we’re encountering actions
for the first time but they are pretty easy to understand.
The data-action
value click->calculate#add
is called an action descriptor. This particular descriptor says:
click
is the event namecalculate
is the name of the controlleradd
is the controller class method to be invoked
CONTROLLER
Creating the corresponding controller should be easy, seeing that we already know our methods and target names. In app/javascript/controllers/calculate_controller.js
, we add the following:
Seeing that the controller is a JavaScript class, we make use of getter methods to get the values of the targets. We also include the add
and subtract
methods which append the newValue
to the currentValue
target.
Did you notice that weird NAN
result? When our input is empty, its value is ""
, and ParseInt("")
results in NaN(Not a number)
. There are several ways of handling this, but here, we’ll handle this within the get addend
method, by returning 0
when the input is empty.
This fixes our NaN
problem and our “calculator” works as expected.
Manipulating an existing HTML document can range from adding a CSS class when certain actions are performed, determining the content of an element, clearing a form after the submit action, to rearranging elements in groupings. Whatever your use case is, Stimulus has got you 🍷.
I strongly recommend the Stimulus Handbook if you would love to delve deeper.
Thank you for reading!