Search code examples
ruby-on-railsstimulusjshotwire-railsturbo

How do I use the "turbo:frame-load" event with Hotwire and Stimulus in Rails?


I'm trying to fire a stimulus event when a Turbo frame has completed updating. In my Rails app, this is setup like the following.

In the view (I'm using slim here):

div data-controller="logger"
  = turbo_frame_tag "europe-calculation-fields",
    data: { action: "turbo:frame-load->logger#log turbo:before-frame-render->logger#log turbo:frame-render->logger#log" } do
    = render "europe_calculation_fields"

My turbo view does this:

= turbo_stream.update "europe-calculation-fields", render("finalize_screens/europe_calculation_fields")

All of this works properly. The finalize_screens/europe_calculation_fields partial is rendered inside the europe-calculation-fields turbo frame as it should be.

But I cannot get any of those frame load or render events to fire. They simply...don't. I have double-checked that the logger#log method is working correctly (it works as expected with a simple click event), and I've checked out the documentation, which says the events should be fired on the frame, so not sure what I'm missing here?


Solution

  • You have to make sure to actually navigate the frame to trigger the related events. If you need to update more than just the frame you can render additional turbo streams inside the frame:
    https://github.com/hotwired/turbo/issues/1258

    <%= turbo_frame_tag "europe-calculation-fields",
      data: {
        controller: "logger",
        action: "turbo:frame-load->logger#log
                 turbo:before-frame-render->logger#log
                 turbo:frame-render->logger#log"
      }
    do %>
      <%= render "europe_calculation_fields"%>
      <%= link_to "action", "/url" %>
    <% end %>
    

    and respond with a matching frame and turbo stream as normal HTML response:

    # app/views/{controller}/{action}.html.erb
    
    <%= turbo_frame_tag "europe-calculation-fields" do %>
      <%= render "europe_calculation_fields"%>
      <%= turbo_stream.update "europe-calculation-fields", render("finalize_screens/europe_calculation_fields") %>
    <% end %>