Jolt: a new target rendering helper for controllers

Hi folks! I’ve soft-launched a new helper library for Stimulus called Jolt. https://github.com/whitefusionhq/stimulus-jolt

Per the README:

Jolt is a simple view rendering library for Stimulus to supercharge your targets. Instead of writing code like this:

this.nameTarget.textContent = "ACME Widgets, Inc."
this.nameTarget.classList.add('text-bold')
this.nameTarget.dataset.id = 25
this.descriptionTarget.innerHTML = descriptionValue

You can write code like this:

this.renderTargets({
  name: [
    "ACME Widgets, Inc.",
    {class: 'text-bold', toggle: true},
    {data: 'id', value: 25}
  ],
  description: {html: descriptionValue}
})

By way of a concrete example, I modified the usual Hello controller Stimulus provides in its initial setup:

// <div data-controller="hello">
//   <h1 data-target="hello.output"></h1>
// </div>

import { Controller } from "stimulus"
import { Renderer } from "stimulus-jolt"

export default class extends Controller {
  static targets = [ "output" ]

  initialize() {
    this.output = "Jolt works! :)"
  }

  connect() {
    this.renderer = new Renderer(this)
    this.render()
  }

  render() {
    this.renderTargets({
      output: this.output
    })
  }
}

I’m still working on docs in the README, but basically beyond just updating targets Jolt provides a few niceties:

  • If a target is missing in the DOM, it silently fails rather than throwing an error.
  • If you reference a target that wasn’t even declared in the controller, it still silently fails.
  • You can optionally pass an HTML template to new Renderer and it will output it into the controller’s element (very easy to do with Webpack’s HTML Loader).
  • You can update classes, attributes, innerHTML or textContent, and data attributes on targets all with this concise syntax.
  • If you set a DOM element’s textContent and it’s the same as what’s already in the DOM, it doesn’t actually update textContent. (Not quite a VDOM but a tiny boost.)
  • If you have a transformNameTarget (whatever your target is called) callback method on your controller, Jolt will pass a value through that method before it sets textContent or innerHTML. You can use callbacks to enforce consistency of data regardless of where/how you’re calling Jolt’s renderTargets.

So what’s the use case of Jolt? I’m thinking it can be used primarily in situations where you need to handle lots of dynamic data (aka JSON) coming down the wire from APIs, whether yours or 3rd-parties. You can use renderTargets to pluck data out of incoming JSON and easily set up your targets’ content, classes, attributes, etc.

If this is starting to feel more like React territory, you’re not wrong. :wink: I’m no fan of React, but coming from more of a Vue background, I do like the general idea of being able to get data out of a wad of JSON an into the DOM quickly and efficiently. I’m hoping Jolt proves to be a nice way to bridge the gap between Stimulus and that need.

I’m announcing this here before I really have docs and tests and such in place because I’m looking for feedback and ideas! I think the API is generally stable hence the 1.0.0 version, and I’m not really looking to alter the existing syntax, but I’m sure there are lots of cool things this could turn into based on community feedback.

Anyway, I hope you try it out and let me know what you think! It’s working now via Webpack/Babel and yarn add stimulus-jolt in your own project — eventually I’ll try to get it working without Webpack/Babel/etc. but for now it will need those build tools.

4 Likes

Awesome work, I’m looking forward to checking it out! PJAX is definitely the sweet spot for Stimulus, but sooner or later you’ll always run into exactly the kind of coding you demonstrated.

Thanks for taking the time to build and share!

-Jeff

1 Like

hey @jaredcwhite
nice work, thanks for sharing

I like your idea of being able to extend one controller capabilities by doing this.renderer = new Renderer(this)
up to now when I build a standard controller, I built it as a full stimulus controller and to use it, you would extend it as a class.
What I like about your approach is being able to mix potentially several controllers into one.

About Jolt, I was wondering how would you do to update multiple targets with the same name but different content for each

1 Like

Thanks — yeah I thought about subclassing Controller for this, but I decided simply to keep it as a separate class and just add an “alias” method to the controller at runtime. If this were Ruby, it would be a mixin for sure.

Regarding array-based targets, I’m still mulling over the best syntax for that. If you have any suggestions, I’m all ears!

1 Like