Stimulus Discourse

Assign AJAX call result to variable

#1

I use Stimulus with Rails.

The process is as follows:

  • click on a button that points to an action in controller
  • action sends AJAX request to API (Rails based)
  • API returns JSON which I want to assign to variable and work on it later (add nodes to a DOM)

I’m struggling to do that because AJAX is asynchronous. Is there any workaround for this?

#2

If you’re working with modern browsers, you could use the Fetch API to perform the request and pick up the response:

<button data-action="data#load">Fetch!</button>
// data_controller.js
load() {
  fetch("https://your-api-url")
    .then(response => response.json())
    .then(json => /* Save the JSON or add notes immediately here */)
}

There’s a section in the Stimulus Handbook on how to work with external resources, if you’re interested in learning more :slight_smile:

#3

The app is only for my personal use so this should work perfectly for me. Don’t know how I missed that thought, probably thought the chapter is just a bunch of links to external resources/tutorials :wink: Thanks a lot!

1 Like
#4

Unfortunately it still doesn’t work. The result is not assigned to variable before I use it, resulting in an empty array at the next executed line (even though it should have two elements). If I put the debugger between the fetch statement and my next line it has enough time to fetch the data.

I did the following:

fetch(url)
.then(response => response.json())
.then(json => subcategories = json)
console.log(subcategories.length) /*returns 0 as on screen*/
debugger /*returns 2 when checked in browser dev tools*/
if (subcategories.length > 0) { /*without debugger it returns false*/

#5

If you want to manipulate the data immediately after the request has finished, you have to do the body of work inside one of the callbacks passed to then, due to the asynchronous nature of fetch() promises.

You can assign the response to a variable like you’re doing in the example above, but you won’t know when it’ll be available. If you’re handling the response inside the same action as you’re fetching it, just enclose it in a promise:

load() {
  fetch("https://your-api-url")
    .then(response => response.json())
    .then(json => {
      if (/* Some requirement */) {
        // Do what needs to be done
      }
    })
}
#6

Thank you, kaspermeyer. I am new to the JS world, but it actually makes sense considering it’s async.

1 Like
#7

Glad to help! :v: Let me know how it goes.