How to Make the Life of Backend Developers Easier in the Monolithic Frontend With Stimulus and StimulusReflex?

Marcin Zgórecki

Feb 3, 2021 • 10 min read

Monoliths are not that popular as they used to be. Today’s applications are split into back-end and front-end with dedicated programmers and servers.

It allows us to separate business logic from graphics and increase an application performance. But what if your client doesn’t have enough money to build separate applications? Or when an application is too small to split? What if we don’t have enough knowledge of Javascript frameworks? No problem! The very simple StimulusJS framework in connection with Rails and the dedicated StimulusReflex gem can do awesome things.

Introduction

I am sure you have built many item listings on an index page with filters, sorting, and an option to add a new item. We can do all these things using two very popular methods:

  • Keeping the information in parameters by clicking the submit button and then refreshing the site with the new data;
  • Using Promises, Ajax , ActionCable - something that could change specific content dynamically.

Adding StimulusReflex to your application will allow you to replace this content dynamically without using Promises or Ajax and without special knowledge of Javascript. StimulusReflex uses ActionCable which you don’t have to write because StimulusReflex will do it automatically for you.

StimulusJS

Stimulus came to life because of the need for JavaScript management in monoliths. It was created by Basecamp for internal use.

It is important to be clear from the beginning - Stimulus is not an alternative for React, Vue or Angular by any means. Stimulus has been created for a very specific goal - monolithic Ruby on Rails applications that need some JavaScript magic served in a convenient way.

The goal of Stimulus is to connect and manage JavaScript in Rails views, as conveniently as possible. JS code is connected to specific parts of Rails views and stored in "Controllers".

The one very important thing to know about Stimulus is that, apart from connecting JavaScript to specific HTML elements in Rails views, it doesn’t do much more. It's just more manageable JS code in monolithic applications, with better structure - JavaScript code divided into controllers. But it can get more interesting when you take Stimulus and add another library to it - Stimulus Reflex.

StimulusReflex

StimulusReflex is a library that enhances the possibilities of Stimulus and Rails - it helps backend developers create reactive applications. Using StimulusReflex and Rails, Reflex can intercept user actions and send them to Rails in real time using WebSockets. Interactions are handled via Reflex Actions that change an application state - Reflex Actions are very similar to the Rails controller. The current page is quickly re-rendered and the changes are sent to the client using CableReady, then the page is morphed (by the morphdom module). According to Reflex’s creators, the whole operation should take around 20-30ms and should not be noticed by the end-user.

Reflex’s creators claim that "This architecture eliminates the complexity imposed by full-stack frontend frameworks without abandoning high-performance reactive user experiences" and that Reflex is a fresh alternative to the Single Page App.

Even if this sounds too good to be true, thanks to Stimulus and StimulusReflex, applications written in Rails can have a new life with a little code and work. Both seem like can be very useful with small and medium applications, helping backend developers create dynamic, reactive applications.

Usage

The table with comments

This example is a simple table with comments. The theory is that clicking the Add comment button adds a new record to the database and then adds a new one to the table dynamically, without page refreshing. It looks like this:

examples comments

The code for the above view is following:

To add Stimulus to our code we have to use special data tags which you find in the documentation. It requires some additional steps:

  • We have to declare the data-controller tag to tell our code that it should be triggered by Stimulus;

  • The data-target declaration tells Stimulus where it should look for value from the input;
  • data-action on button declares a click event which will trigger the addComment function in the JS controller;

  • The comments table also should be a target to tell Stimulus where items are defined.

If our HTML is ready, it’s a good time to create our JS controller app/javascript/controllers/comments.js.

addComment is triggered via the action which we declared at the button (data-action="click->comments#addComment”). Easy, right?

As you can see, Stimulus is a bit like an interface thanks to which we can manage the logic of scripts very easily. But we can do it much easier - without fetching data via an API or preparing and inserting HTML parts. Let’s see how it looks using StimulusReflex.

Our HTML won’t be changed a lot. The only thing is that <div id=”comment_items”> does not have to be a target because elements will be added dynamically from the Rails Controller. However, our JS controller will look much different.

It means that the addComment method calls "create" in the CommentsReflex class via the .stimulate() method provided by StimulusReflex. The second parameter is a value from the input which we want to send to the create method. create is declared in the app/reflexes/comments_reflex.rb file.

That’s all. StimulusReflex does not require anything more. The Rails controller looks very simple (code below) and the effect is very impressive.

We can freely extend the CommentsReflex class with new functionalities which could be returned on the site - for example you could set new flash messages and inform users about the status of an operation dynamically.

Infinite scroll, Stimulus example

In this example, we implement an index view of elements with pagination (using the Pagy gem) and use Stimulus to connect HTML elements with a JavaScript controller to create an infinite scroll and hide the pagination button.

The final goal was to have this (while scrolling down):

Instead of this:

This example is pretty basic, but it shows nicely how Stimulus helps you with code organization.

Our erb template looks like this:

As you can see, attaching HTML elements to the Stimulus controller is super easy, and so is specifying the targets - thanks to passing them to the JS controller, we can manipulate them.

When it comes to the JavaScript controller - it is as good as your JS skills, so in my case, it's poor. But it gets the job done.

When using Stimulus, JavaScript code is organized in Controllers. The base controller looks like this.

Let's see what's inside our InfiniteScrollController.

`targets` are our list of all targets we specified in our HTML view. Later in this controller, we will be able to refer to them as `paginationTarget`.

For example:

The major benefit we get from pure Stimulus is a readable template with JS connected to specific HTML elements, as well as clear targets that we send to the Stimulus Controller.

More fun awaits us with Stimulus Reflex examples.

Pagination without reloading a page, Stimulus Reflex example

Let's move to the fun part - StimulusReflex. This example will show a way of implementing pagination (classic approach this time, not infinite scroll) using Pagy, but without page reload.

Let's start by connecting our table with the Stimulus controller using the data-controller attribute. We are also telling StimulusReflex that our DIV is a root and it should reload only its content, but nothing outside of it - data-reflex-root="#dashboard-table".

Let's move to the StimulusReflex Controller. In its basic form it looks like this:

The new element that Stimulus Reflex brings is the Reflex file. It lives in the app/reflexes/ directory in the Rails structure. Our Reflex class is very simple - its job is to get the current page number from JavaScript Controller and set it so that the Rails controller knows which page to load.

This specific information is sent from the JavaScript controller. First, we extract the page number and then we call the Reflex class.

To have a full view, here is our Rails controller's action for this view.

And that's it - with this setup, our backend provides us with a paginated collection of items. Stimulus and StimulusReflex extract and send the desired page number to the backend. Backend fetches the page and returns it via CableReady to Stimulus Reflex. StimulusReflex morphs the page giving us the final result - pagination without reloading.

Marcin Zgórecki & Kamil Chodorek

More posts by this author

Marcin Zgórecki

Codestories Newsletter