8

I am using Turbo Frames in my Rails app and have, on every page

<turbo-frame id="messagesFrame" src="/chats">
</turbo-frame>

This loads in fine, and when a link is clicked replaces the frame as expected. In this frame I have set overflow-y: scroll, creating a scrollable frame on the page. Every time a new page is loaded in the frame, I want it to scroll to the bottom. How can I achieve this? Ideally with vanilla JavaScript.

tsvallender
  • 2,615
  • 6
  • 32
  • 42

1 Answers1

17

You could do this in several ways.

Turbo should fire a turbo:before-fetch-request and turbo:before-fetch-response on the document when lazy loaded frames, or links that trigger a frame reload.

You could do something like:

document.addEventListener("turbo:before-fetch-response", function (e) {
  let frame = document.getElementById("messagesFrame");
  if (frame.complete) {
   frame.scrollTo(0, frame.scrollHeight)
  } else {
    frame.loaded.then(() => frame.scrollTo(0, frame.scrollHeight))
  }
})

Sources: Turbo events => https://turbo.hotwired.dev/reference/events

Frame.complete and Frame.loaded => https://turbo.hotwired.dev/reference/frames


I suggest the above method because you specified vanilla Javascript. The recommended way for most Turbo related things is to use StimulusJS.

You could write a Stimulus (https://stimulus.hotwired.dev/) controller that you attach to an element in the body that shows inside the TurboFrame, and in the connect method, do the same.

That way, whenever the content inside the frame is refreshed the Stimulus controller will run, and you don't have to worry about the order of the events being fired.

hananamar
  • 1,166
  • 15
  • 25
SubXaero
  • 367
  • 3
  • 8
  • Thanks! Going for the Stimulus version (only stated vanilla to avoid JQuery, new to this and forgot Stimulus existed), but the code throws "frame.loaded is undefined". If I get rid of the if statement and just run scrollTo(), it's working great, is the if statement just to make sure it's loaded first? It's also injecting a bunch of whitespace near the top of the page for some reason :-\ – tsvallender Apr 29 '21 at 12:21
  • Not sure what it was but various CSS changes I've been making seem to have done away with the whitespace issue. – tsvallender Apr 29 '21 at 12:47
  • Yes, depending what version of turbo/hotwire you're running. In the latest version (beta-5) `loaded` is a property that returns a promise that resolves when the frame finishes loading. – SubXaero Apr 29 '21 at 16:38
  • You shouldn't need the `if` statement when using a stimulus controller in the frame content, as the controller only runs when the frame finishes loading :) – SubXaero Apr 29 '21 at 16:40