Hotwire Discussion

Prevent history change on turbo-stream response

Hi,

I’m enjoying turbo, don’t know if I’m using it correctly, but I’m enjoying it a lot :).

My use case is this: For a given model the “show” template is pretty simple, so I don’t wanna render an entire page for them, I just wanna generate some sort of tooltip inside the “index” page. I put a div with the corresponding id to receive the html and then did render with turbo_stream.replace. Works exactly like I wanted, however, the history of the browser is changed with the url ‘/products/:id’. But I wanna keep the history on the show action ‘/products’, since I don’t want the user to be able to manually navigate to ‘/products/:id’. Actually, most of the page is still ‘/products’, since just the tooltip part is the current product.

Any setting, parameter to change this behavior for this particular case?

I can do it if the link_to have the property data-turbo-frame, and I have a corresponding turbo_frame_tag. But I wonder if there’s another easier way.

This is the approach I would suggest for this scenario.

I actually did a little better this time. The data-turbo-frame property is kinda coupled with the turbo_frame_tag via the id property. I don’t like this, because the turbo_stream response already have the instructions on where to perform the changes. What I did was a simple Stimulus controller, very naive implementation:


// turbo_fetch_controller.js
import { Controller } from 'stimulus';
import { get } from '@rails/request.js';

export default class extends Controller {
  connect() {
    let url =  this.element.href;
    this.element.addEventListener('click', (e) => {
      e.preventDefault();
      get(url, { responseKind: 'turbo-sream' });
    })
  }
}

All I need now is data-controller: "turbo-fetch"
o/

2 Likes

Great suggestion! I’m going to steal this code (you have a typo in turbo-sream, should be turbo-stream).

1 Like

I actually improved it a little bit by dispatching turbo:before-fetch-request, which is the event that I see fired by turbo when I don’t hijack it. For some reason, it still prevent history change doing that so fine by me, I’m guessing that turbo fires on a later stage on the the Event stack (later than ‘click’ for sure). I think is a good idea to send the event to minimize possible side effects. I also rely on it to handle loading states.

Thanks for the tip on the typo, I actually introduced it on an [edit] on the post.

Error handling is still missing, pretty naive implementation as I said. I use rails to build tools for my own personal use, mostly to manage my own business, so I don’t worry too much with that stuff, guess I’m not a real developer =/

Here’s the updated snippet:

import { Controller } from 'stimulus';
import { get } from '@rails/request.js';

export default class extends Controller {
  connect() {
    let url = this.element.href;
    this.element.addEventListener('click', (e) => {
      e.preventDefault();
      document.dispatchEvent(new Event('turbo:before-fetch-request'));
      get(url, { responseKind: 'turbo-stream' });
    });
  }
}