Stimulus in rails

Tejal Panjwani
7 min readFeb 28, 2023

--

Hotwire has launched form Rails 7, which also comes with the Stimulus component.

The JavaScript framework called stimulus has modest goals. It isn’t interested in rendering HTML at all, and it doesn’t want to take over your entire front-end. Instead, it’s intended to add just enough behaviour to your HTML to make it stand out. Stimulus and Turbo-links work great together to provide a complete solution for quick, interesting apps with the least amount of work.

Such as drag and drop, endless scroll, dynamic search, and filtering are some examples of stimulus.

Controllers, actions, targets, and values are some of the important concepts in stimulus.

Let’s first study each concept in depth, then we’ll see two examples of it — one for fetching data, such as a GET request, and another for database modifications, such as inserting, deleting, and modifying records — so that we can learn how to update data into databases using stimulus.

Controllers:

Controllers are JavaScript class objects where javascript code is written. Controllers contain functions which are called when an event occurs.

The controller base class exported by the @hotwired/stimulus module is the one that all controllers classes inherit from.

How to create a stimulus controller:

When you integrate the hotwire gem at that moment, the default hello_controller.js file will be created under the app/javascript/controllers/ directory.

Run the command below to generate another javascript controller file.

rails generate stimulus controllerName

The above command creates a controller and automatically executes the rails stimulus:manifest:update command, which registers a controller with an identifier into the app/javascript/controllers/index.js file. If the index.js file isn’t already present in the app/javascript/controllers directory, the index.js file will be created under the app/javascript/controllers/ directory and the controller’s identifier will be registered.

Generate stimulus controller using command

If we manually add a controller to the application and then run rails stimulus:manifest:update command, a controller’s identifier is automatically registered in the app/javascript/controllers/index.js file. If the file is missing, it will be created and a controller’s identifier will be registered.

We can manually register the controller’s identifier, by first importing the controller class and then calling the application#register function into your application. Write below code into app/javascript/controllers/index.js file.

Here, “example” acts as an identification for ExampleController, and we utilise a data-controller attribute with html elements.

Actions:

Via actions we handle DOM events into controllers. Action is a combination of DOM events, the controller’s name, and its function. The DOM has events like click, change, and focus.

A data-controller attribute must be added to the parent element for add action.

An action descriptor, which can be written as
DOMEvent->controllerName#functionOfController” is also used to define an action.

In this case, search is a function of search controller which is executes on each key-press event.

Targets:

Use targets to refer the HTML elements by name into controllers. Means target is a way to connect an HTML element to the controller such that its value, attributes, properties can be accessed inside the controller.

Include the data-target attribute, which refers to the controller’s name and another which refers to an HTML element’s name. As a result, in the example above, the params refers to an HTML element’s name and search refers to the controller’s name.

Let’s now include the target in the controller.

To define target names in your controller, use the static keyword together with a local variable name to targets as array. If you have multiple targets, create an array by separating each item with a comma.

Targets are represented as array.

Use the following controller method to access an HTML element:

 this.[name]Target

This allows us to obtain an HTML element for the params target paramsTarget

 this.paramsTarget

It will return HTML element

Access HTML element by target

Values:

HTML data attributes can be read, written to, and observe in controllers.

For example, controllerName-variableName-value could be added as an attribute for HTML elements. Here, the variable’s name is URL and the controller’s name is make-as-read-unread.

As a result, make-as-read-unread-url-value would be the attribute for the HTML element in this scenario.

Values attribute with HTML element

Stimulus controllers support DataTypes that automatically map to data attributes.

Targets are represented as array, whereas Values are represented as hashes.

In this case DataTypes can be Array, Boolean, Number, Object or String. How the value is converted between JavaScript and HTML depends on the DataTypes.

Values are represented as hashes

Access value properties into the controller.js as follows:

   this.[name]Value

We have two values here. Two examples are URL and storyId. In order to access this value into the controller.js, do as follows:

let url = this.urlValue
let story_id = this.storyIdValue

The values that were assigned to HTML elements and DataType provided into the controller.js will be returned.

Let’s see dynamic search example with GET method

Dynamic Search:

Let’s build a controller for story search. To establish a search controller, generate stimulus search and run below command:

rails generate stimulus search

Under the app/javascript/controllers directory, a search_controller.js file will be created.

Moreover, SearchController will be imported and registered in the app/javascript/controllers/index.js file with automatically run the rails stimulus:manifest:update command.

Let’s add a search box to app/views/stories/index.html.erb after creating the controller.

Search box’s HTML element with controller and action

A text_field_tag which is an HTML input element is connected to a class in the search_controller.js file through a data-controller.

The data-action indicates that when we enter text into a search box, a search method’s code from search_controller.js will be executed.

In this case, InputEvenet can be used in place of ChangeEvent. InputEvent occurs when an input element is changed, while ChangeEvent works on focus out.

The event InputEvent is used to update search items on each key-press, hence the current data-action value is input->search#search.

With data-target, an HTML input element is accessed in search_controller.js by the name of the params.

Search controller with search function

Here search function called app/controllers/stories_controller.rb of search action (stories#search) from fetch API.

Called stories#search

Attached video of search functionality.

Search functionality with stimulus

Let’s check examples of database changes with the PATCH method with fetch API.

Mark as read and unread story

We should give stories the ability to be marked as read or unread functionality.

One field with the name mark_as_read and a boolean DataType should be implemented. If the mark_as_read value is true, the story has been read; if the mark_as_read value is false, the story is still unread. The default value should be added as false.

The creation of a migration for the make_as_read field as below and add default as false.

rails g migration AddMarkAsReadInToStory mark_as_read:boolean
Mark as read migration

Run the following command in the terminal to make the modifications into the database of your application.

rails db:migrate

Use the mark_as_read field into the application now. Build make_as_read_unread_controller.js under app/javascript/controllers/ directory by rails command which is mentioned below

rails generate stimulus make_as_read_unread
Create make_as_read_unread stimulus controller

There are two actions. One has been read, the other has been unread. Add actions as function into app/javascript/controllers/make_as_read_unread_controller.js

Stimulus make_as_read_unread_controller.js

Let’s now execute actions read and unread using the view part. For read and unread functionality, Add the envelope-open icon for read and the envelope icon for unread icon.

Read and unread functionality with icon

In this case, utilise stimulus’s value property with link_to tag to use the URL and story_id values in the app/javascript/controllers/make_as_read_unread_controller.js script.

Here, we utilised the URL value with the fetch API to instruct the API to run a rails controller’s action, and we used the story_id to update a specific story’s HTML into the DOM at runtime.

We build hash-object for local variables as values with the static keyword, and add URL as key and string data-type as value and storyId as key and number data-type as value in app/javascript/controllers/make_as_read_unread_controller.js script.

Get value by using this.[name]Value which is define in read and unread function into controller as below:

Read and unread function into stimulus app/javascript/controllers/make_as_read_unread_controller.js

To inform a request that it is a patch request, we define the method as PATCH into fetch API.

When we use the fetch API It will be called the rails controller’s action. Here, read and unread action from stories_controller.rb

Action of rails controller for update mark_as_read field

In this case, the returned response is HTML markup in JSON format. The HTML for a specific story_id will then be modified with the result html.

Attached video of mark as read functionality.

Mark as read and unread functionality

👉 Source code

Please like and share if you like reading this. And please don’t hesitate to contact me if you have any questions. I’m grateful you took the time to read this tutorial🙌.

--

--

Tejal Panjwani
Tejal Panjwani

Responses (2)