Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

turbo:frame-load in turbo_stream not triggering #379

Open
Nerian opened this issue Aug 30, 2022 · 4 comments · May be fixed by hotwired/turbo#702
Open

turbo:frame-load in turbo_stream not triggering #379

Nerian opened this issue Aug 30, 2022 · 4 comments · May be fixed by hotwired/turbo#702

Comments

@Nerian
Copy link

Nerian commented Aug 30, 2022

Hi,

I am trying to execute some common JS code whenever the contents of a turbo-frame are rendered. But I am having some issues when the turbo-frame is updated via turbo_stream. It seems like the turbo:frame-load event is not happening.

edit.html.slim

= turbo_frame_tag @academic_year do
        = render partial: 'details'

academic_years_controller.rb

def update
  ...
  respond_to do |format|
    format.turbo_stream      
  end
end

update.turbo_stream.erb

<%= turbo_stream.update(dom_id(@academic_year), partial: 'details') %>
$(document).on('turbo:frame-load',function() {
  console.log('turbo:frame-load');
})

I don't see the turbo:frame-load happening, despite the fact that the frame is correctly updated.

What am I misunderstanding? How can I execute code after a frame is updated via turbo_stream?

Thanks

@Nerian Nerian changed the title turbo:frame-load in turbo_stream turbo:frame-load in turbo_stream not triggering Aug 30, 2022
@seanpdoyle
Copy link
Contributor

Currently, a turbo:frame-load event is only dispatched after the frame's contents have been fetched from an HTTP response. The same is true for turbo:frame-render.

Having said that, I could see a case for dispatching a turbo:frame-render when a <turbo-frame> element connects to the document, and continuing to dispatch a turbo:frame-load whenever it retrieves its contents over HTTP.

Unfortunately, the current implementation and documentation for turbo:frame-render mentions that the detail.fetchResponse property references the HTTP response, which would not be present on an initial rendering of the element.

I'll open a Pull Request against hotwired/turbo to propose changing that.

In the meantime, you might want to declare a Stimulus controller, render [data-the-controller-target="frame"] on the <turbo-frame> element (the original and the one in the <turbo-stream> response), then declare a Target Connected Callback in that controller to have a hook for handling a newly connected Frame element.

seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Aug 30, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
@seanpdoyle
Copy link
Contributor

I've opened hotwired/turbo#702 to explore the implications of dispatching turbo:frame-render whenever a Frame element is connected to the document.

@Nerian
Copy link
Author

Nerian commented Aug 30, 2022

Amazing, thanks 🥳

seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 1, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 14, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 14, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 14, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 14, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Sep 27, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Dec 30, 2022
Closes hotwired/turbo-rails#379

Currently, a `<turbo-frame>` element only dispatches events when its
contents are fetched over HTTP. The `turbo:frame-render` and
`turbo:frame-load` events are dispatched sequentially and immediately
following one another. The `turbo:frame-render` detail exposes a
reference to the `FetchResponse`, while the `turbo:frame-load` event has
no details.

Consumer applications might expect a `<turbo-frame>` to dispatch a
`turbo:frame-render` event immediately whenever a `<turbo-frame>` is
connected to the document (similar to the way that `turbo:render` is
dispatched prior to `turbo:load`, even on restoration Visits).

For the sake of consistency and distinguishing between two events that
are more or less equivalent and temporally interchangeable, this commit
proposes that a `<turbo-frame>` should dispatch a `turbo:frame-render`
_whenever its contents change_, including its initial render.

As a complementary change to that behavior, the `turbo:frame-load`
events will be dispatched with `detail.fetchResponse` as a reference to
the `FetchResponse`.

Ideally, the `turbo:frame-render` would not expose the
`detail.fetchResponse` reference. However, removing it would be a
breaking change. To that end, this commit dispatches a `detail` that
prints a console warning (encouraging a migration to `turbo:frame-load`)
whenever a `turbo:frame-render` listener reads the
`detail.fetchResponse` property. Future major releases can remove the
property and warning.
@justinjdickow
Copy link

justinjdickow commented Mar 6, 2024

Just adding detail to the implementation mentioned.

If you have a stimulus controller that has the method you want to execute already attached to some view then your turbo stream can render the view with a local like

<%= turbo_stream.append "somethings" do %>
  <%= render @something_new, do_something: true  %>
<% end %>

when the view renders you can conditionally connect a new controller

<div id="somethings_<%= @something_new.id %>"  data-controller="the-existing-controller <%= local_assigns[:do_something] ? " the-new-controller" : "" %>"
...
</div>

And the new controller can call the existing controller's method

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    const existing_controller = this.application.getControllerForElementAndIdentifier(this.element, "the-existing-controller");
    existing_controller.doSomething();
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

3 participants