Stimulus Discourse

Turbolinks and POST requests

I just gave StimulusJS for a personal fun project a try and I’m very happy with it. Next step is using Turbolinks, but I’m missing something:

My app is currently executing “rest-like” calls using the fetch API using a workflow like this:

  • Click event is connected via a Stimulus controller.
  • Event handler in the controller uses the fetch API to communicate with the server, using GET, POST, PUT, DELETE requests.
  • I get server side rendered html back, parse it and replace parts of the page.

I would like to replace the second part with Turbolinks, but don’t see how to specify the request to be executed. Do I miss something or is that just not possible. How do you pass data to the server when using Turbolinks? Of course I could post data via fetch and navigate via Turbolinks afterwards, but that would be two server requests instead of one.

As all of this is rather simple and default stuff, I’m probably missing something or just get the scope of the project wrong. Could somebody enlighten me? :wink:

Hey Achim_Domma!

I’ll start my response off by making sure we’re on the same page with Turbolinks. Turbolinks is fundamentally different than your current approach. Turbolinks expects an entirely new page to be loaded to replace the current page - it doesn’t come into play when replacing only pieces or parts of a page via AJAXy/single page app approaches. The two aren’t mutually exclusive by any means, it’s just Turbolinks doesn’t come into play here. Turbolinks is really meant to speed up “standard” web interactions (clicking links, submitting forms) but not reloading (even from cache) all JS and CSS and then reparsing all of that data. It also makes use of a local cache to feel even snappier. And it’s meant to all be pretty transparent to both dev and user.

Alright, with that out of the way - If you want to ditch the custom JS altogether, you could use a form for each action and just submit the form using the correct method (e.g. POST) and let the server render the correct result. No need to explicitly trigger Turbolinks at all, it’ll “just work”.

Now let’s assume you want to stick with the current JS approach. Let’s say your stimulus controller makes a DELETE request. You would want to listen for the success of that request and then call Turbolinks.visit() to go to the current page afterwards. You likely want to clear the Turbolinks cache, as well, so that Turbolinks doesn’t present the now deleted data form it’s local cache.

So let’s say you’re on page /products and click a delete button (passing any data, such as a product ID, via the Fetch API). In your fetch success handler, you’d do something like:

Turbolinks.clearCache()
Turbolinks.visit("/products", {"action":"replace"})

This would clear the cache and effectively reload the current page, which would be rendered by the server and no longer include the deleted item. It’s as simple as that.

Interestingly, if using a remote form in Rails (form_with model:@foo, remote: true), the Turbolinks Rails engine will actually send back the two lines of Javascript above and execute it on the client.

I hope this was helpful. I’d be curious to hear if based on your actual use case Turbolinks still seems like the path you want to go down here!

1 Like

First of all, thanks for the nice explanation, which made my mental model of the whole thing much clearer. I will give the pattern with “sending back two lines of JS” a try. I have one “special case” where I might have to dig in to the “data-turbolinks-permanent” feature. So I’ll probably be back with more questions.

1 Like

Just FYI: I’m using Turbolinks with success. It made my code much simpler in most cases. I have some cases where the reload lets the page “jump”, but I’ll somehow be able to manage this.

1 Like

Nice, glad to hear it! Feel free to follow up if you need any help with the jumps.