Benito Serna
Trying to build software that works

Less code in your javascript sprinkles with Stimulus.js

If you are thinking in trying Stimulus.js in your project, maybe this little “before and after” can help you to decide.

Today I was porting a small functionality to send some data to our analytics service from a “data-behavior” style of javascript sprinkles to Stimulus.js….

And I found very interesting that a lot of the code that we had to implement the feature was just to listen for the events and get the data from the html.

This was the previous code…

namespace = "project-item-track-click"
selectorFor = (name) -> "[data-behavior~='#{namespace}:#{name}']"
itemSelector = selectorFor("item")
containerSelector = selectorFor("container")

$items = ->
   $(item) for item in $(itemSelector)

$linksForItem = ($item) ->
   $(link) for link in $item.find("a")

getUserReferralCode = ->
  $container = $(containerSelector)
  $container.data("user-referral-code")

getRemainingDays = (targetDate) ->
  diff = moment(targetDate).diff(moment(), "days") + 1
  if diff > 0 then diff else 0

buildEventDataForItem = ($item) ->
  data = {}
  rawData = $item.data("for-event-tracking")
  data[key] = value for key, value of rawData when key isnt "target_date"
  data.remaining_days = getRemainingDays(rawData.target_date)
  data.user_referral_code = getUserReferralCode()
  data

initialize = ->
  for $item in $items()
    for $link in $linksForItem($item)
      analytics.trackLink($link[0],
        'Campaign Details Clicked',
         buildEventDataForItem($item))

$(document).on "ready page:load", initialize

You can like the code or not, but look how although “our logic” was almost just on the function buildEventDataForItem and getRemainingDays… It was needed to write some funky and custom code to initialize the behavior and get the needed data from the html.

This is now the code using Stimulus.js

import { Controller } from "stimulus"
import moment from "moment"

export default class extends Controller {
  connect() {
    let data = JSON.parse(this.data.get("eventData"));
    this.setRemainingDaysOn(data);
    this.setUserReferralCodeOn(data);
    analytics.trackLink(this.element, "Campaign Details Clicked", data);
  }

  setUserReferralCodeOn(data) {
    let code = document.body.dataset.userReferralCode;
    data.user_referral_code = code;
  }

  setRemainingDaysOn(data) {
    let targetDate = data.target_date;
    delete data.target_date
    data.remaining_days = this.remainingDays(targetDate)
  }

  remainingDays(targetDate) {
    let diff = moment(targetDate).diff(moment(), "days") + 1

    if (diff > 0) {
      return diff
    } else {
      return 0
    }
  }
}

Again, you can like the code or not, but look how now almost all the code here is related to “our logic”… Now Stimulus.js is giving us an easy and standard way to initialize the behavior and fetch the data from the html.

I think is a nice improvement, don’t you think?

Do you need some help with TDD?

I have an email course with with a guide to help you start with TDD!


Do you want to know more?