Skip to content

Blogging On Rails

Everything on Rails!

Loading and Templating JSON Responses in Stimulus.js

Just because Stimulus.js is designed to work with HTML over the wire doesn’t mean it can’t use JSON APIs when the need arises.

Loading Github Commits

In fact, it can perform just like Vue.js in pulling JSON from an API and placing the results on your page. Here is a tutorial that loads commit messages from Github, and renders them in a list. There is no templating library used, since ES6 strings in Javascript are very succinct and will cleanly concatenate strings. 

The HTML

The wrapper div houses the controller, and has the commit message url. There is a set of radio buttons to load commits for different branches, just like in the Vue.js example. The current branch text is changed when a radio button is selected, and the commits are loaded and inserted into the commits.commits target.

<div data-controller="commits" 
     data-commits-url="https://api.github.com/repos/rails/rails/commits?per_page=15&sha=">
    <h1>Latest Rails Commits</h1>
    <input data-action="change->commits#selectBranch" 
           data-target="commits.option" 
           type="radio" 
           name="branch" 
           value="master" checked> 
    <label for="master">master</label>
    <input data-action="change->commits#selectBranch" 
           data-target="commits.option" 
           type="radio" 
           name="branch" 
           value="5-2-stable"> 
    <label for="5-2-stable">5-2-stable</label>
    <input data-action="change->commits#selectBranch" 
           data-target="commits.option" 
           type="radio" 
           name="branch" 
           value="5-1-stable"> 
    <label for="5-2-stable">5-1-stable</label>
    <p>rails/rails@<span data-target="commits.branch"></span></p>
    <ul data-target="commits.commits">
    </ul>
  </div>

The Controller

The controller will be responsible for loading the commits for a branch, generating the HTML, and then inserting them into the commits <ul>. The controller also loads the commits for the master branch when it is connected to the dom. Selecting a branch calls the selectBranch() method, which then loads the commits. 

The loadBranch() function fetches the commits from Github’s API and then converts the data to a JSON object. The HTML is generated from the commitTemplate() function, which is just concatenates the string for a single commit object. 

There are two other helper functions, truncate() and formatDate(), which come from the Vue.js example.

import { Controller } from "stimulus"

export default class extends Controller {

  static targets = ["option", "branch", "commits"]
  
  connect() {
    this.optionTargets.forEach((el, i) => {
      if (el.checked) {
        this.loadBranch(el.value)
      }
    });
  }

  selectBranch(event) {
    this.loadBranch(event.srcElement.value);
  }

  loadBranch(branch) {
    this.branchTarget.innerHTML = branch;
    this.commitsTarget.innerHTML = `<li>Loading comits for ${branch}</li>`
    var commitHTML = "";
    fetch(`${this.data.get("url")}${branch}`)
    .then( data => {
      return data.json(); 
    }).then( commits => { 
      var commitsHTML = "";
      commits.forEach((commitJSON) => {
        commitsHTML += commitTemplate(commitJSON);
      }); 
      this.commitsTarget.innerHTML = commitsHTML;
    });
  }
}

function commitTemplate(commit) {
  return ` <li>
      <a href="${commit.url }" target="_blank" class="commit">${ commit.sha.slice(0, 7) }</a>
      - <span class="message">${ truncate(commit.commit.message) }</span><br>
      by <span class="author"><a :href="record.author.html_url" target="_blank">${ commit.commit.author.name }</a></span>
      at <span class="date">${ formatDate( commit.commit.author.date ) }</span>
    </li>`;
}

function truncate (v) {
  var newline = v.indexOf('\n')
  return newline > 0 ? v.slice(0, newline) : v
}
  
function formatDate(v) {
  return v.replace(/T|Z/g, ' ')
}

Templating With Stimulus

Without the need for a third party templating library, you can wrap your string concatenation code inside a function, and then pass the data you want in the template as an object. This works really well with JSON, since everything is already an object, and is no more difficult than importing a library, parsing a template, and binding values from an object. With multiline strings, enclosed by a “ pair and the ${} concatenation, your html can still look crisp. And wrapping it into a function will keep your main logic clean.

Stimulus loves JSON

Your Stimulus controllers can add some JSON API functionality, especially when it’s from a service that doesn’t have HTML. No need to rewrite your Rails app into a single, full page web app. You can sprinkle on a little Stimulus, and use any data source.

Feel free to leave a comment or question below.

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.

4 comments on “Loading and Templating JSON Responses in Stimulus.js”

    1. Thanks, that was copied over from the Vue example, and I missed updating it. It’s not having any effect in this example.

Leave a Reply

Your email address will not be published. Required fields are marked *

Copyright © 2024 John Beatty. All rights reserved.