-
Notifications
You must be signed in to change notification settings - Fork 428
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
Introduce turbo:frame-missing
event
#445
Conversation
6aa1ccd
to
eb3c925
Compare
c613b77
to
18c1c64
Compare
In the above example, does |
@tleish if there's a https://github.com/hotwired/turbo/blob/v7.1.0-rc.1/src/core/drive/visit.ts#L171-L173 As part of this draft, I'm investigating ways to more easily transform the |
7904c5f
to
a62fa18
Compare
5af1e0b
to
712516d
Compare
A good solution. It would be even better if a developer didn't have to recreate response object. Something like: addEventListener("turbo:frame-missing", async ({ target, detail: { fetchResponse } }) => {
// the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
// are up to the application to decide
if (shouldRedirectOnMissingFrame(target)) {
Turbo.visit(fetchResponse.location, { response: fetchResponse })
}
}) Learned something new, thanks! |
Working beautifully for the most part. But I think I'm running into a bug? I'm using the exact code sample suggested: addEventListener("turbo:frame-missing", async ({ target, detail: { fetchResponse } }) => {
const { location, redirected, statusCode, responseHTML } = fetchResponse
const response = { redirected, statusCode, responseHTML: await responseHTML }
Turbo.visit(location, { response })
}) The first time this event is triggered by a form submission, it works great – the whole page is replaced with the new HTML. But if I repeat the submission a second time, it breaks. Turbo seems to revert to a cached snapshot of the whole page, and never completes the visit ( |
I'll investigate that. I'm not sure if it's related, but it's also worth mentioning that if you're using turbo-rails, you'll have to manually override the controller to render a layout so that the response is a fully formed HTML document. |
Assuming 'frame-missing' still logs a message to the console, should Turbo.visit also log a message of "responseHTML not a fully formed HTML document"? |
@tobyzerner - this might be unrelated to these changes as I think I stumbled across a similar issue on 7.0.1.
What I observed is that turbo renders the page and fetches the turbo-frame source. Inspecting the fetch request I can see in includes a full HTML document with the expected updates and the correct turbo-frame. It just does not update the turbo-frame. Adding @seanpdoyle - If needed, I can file a separate issue. |
Turns out this has nothing to do with turbo-frames, but overall turbo-caching and server redirects. Created issue #447 |
f0f0dee
to
6eb8444
Compare
@tleish I've extended the |
ed273ca
to
84a737b
Compare
Will this be in the next release? |
I'm not sure when the next release will be. I've marked this as a Draft PR to try and start up a discussion. I think there might be some details to work out:
|
Hey guys, any updates ? |
I arrived here from the thread in #257 and am looking a solution to the exact use case mentioned above and am wondering if there are plans for this event to be added to Turbo Frames (or if another solution is in the works) |
Could this be a good candidate for inclusion in 7.2.0? An alternative could be to combine the PR in #560 introducing |
this should be merged. |
I've opened hotwired/turbo-rails#367 to explore an alternative for "breaking out" of a frame from the server. As far as what happens when a frame is missing, that seems to be an ongoing discussion. |
84a737b
to
67c0826
Compare
Closes [hotwired#432][] Follow-up to [hotwired#94][] Follow-up to [hotwired#31][] When a response from _within_ a frame is missing a matching frame, fire the `turbo:frame-missing` event. There is an existing [contract][] that dictates a request from within a frame stays within a frame. However, if an application is interested in reacting to a response without a frame, dispatch a `turbo:frame-missing` event. The event's `target` is the `FrameElement`, and the `detail` contains the `fetchResponse:` key. Unless it's canceled (by calling `event.preventDefault()`), Turbo Drive will visit the frame's URL as a full-page navigation. The event listener is also a good opportunity to change the `<turbo-frame>` element itself to prevent future missing responses. For example, if the reason the frame is missing is access (an expired session, for example), the call to `visit()` can be made with `{ action: "replace" }` to remove the current page from Turbo's page history. [contract]: hotwired#94 (comment) [hotwired#432]: hotwired#432 [hotwired#94]: hotwired#94 [hotwired#31]: hotwired#31
67c0826
to
3a20497
Compare
src/core/session.ts
Outdated
@@ -305,6 +305,13 @@ export class Session | |||
this.notifyApplicationAfterFrameRender(fetchResponse, frame) | |||
} | |||
|
|||
async frameMissing(frame: FrameElement, fetchResponse: FetchResponse): Promise<void> { | |||
const responseHTML = await fetchResponse.responseHTML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since servers (like Rails) can respond to Frame requests with incomplete HTML documents, I'm unsure about how to best handle a response without a matching frame.
I'm not sure whether or not Drive should re-use the response HTML or issue a new request to fetch a full page of content. My gut tells me to always make a full request, but I'm curious if there's a quick win I'm not considering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current default is correct, because the majority case here will be to deal with pages like 500 errors or authentication expired errors, where full pages will be returned. But I think we can help developers here by logging a warning to point them in the direction of what's going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see you changed it to a full visit instead. I guess it doesn't matter that much. This behavior is for the exceptional case in any circumstance. Not for the normal, steady flow.
…missing matching frame
* main: Add turbo:fetch-request-error event on frame and form network errors (hotwired#640) Return `Promise<void>` from `FrameElement.reload` (hotwired#661) Replace LinkInterceptor with LinkClickObserver (hotwired#412) Don't convert `data-turbo-stream` links to forms (hotwired#647)
Would be good to follow up with a doc PR explaining the new event and its power to prevent the default visiting fallback behavior. |
After re-considering a comment on [hotwired#445][], this commit re-purposes the response HTML from the `FetchResponse` instance, instead of issuing a follow-up HTTP request. [hotwired#445]: hotwired#445 (comment)
After re-considering a comment on [hotwired#445][], this commit re-purposes the response HTML from the `FetchResponse` instance, instead of issuing a follow-up HTTP request. [hotwired#445]: hotwired#445 (comment)
After re-considering a comment on [#445][], this commit re-purposes the response HTML from the `FetchResponse` instance, instead of issuing a follow-up HTTP request. [#445]: #445 (comment)
Turbo 7.2 introduces the event `turbo:frame-missing` if the response doesn't contain a matching frame. If this event is fired, Turbo will perform a full-page navigation. This allows to simplify a common use-case with forms in modals: - the form is rendered with a `<turbo-frame id="modal-content">` and is loaded in the modal - when the submitted form is successful, the controller returns a response _without_ any turbo-frame with id `modal-content` (and so Turbo follows the redirection) - when the submitted form contains error, the controller returns the form with errors in a turbo-frame with id `modal-content` (and so Turbo loads its content in the modal) Before that, I had to use a pretty complicated hack based on Turbo Stream which rendered the forms conditionnaly with the normal layout (e.g. `feeds/new.phtml`) or in a `<turbo-stream>` element (e.g. `feeds/new.turbo_stream.phtml`). Now, the expected behaviour comes for free, I just have to declare a view to be available for modals :). Reference: hotwired/turbo#445 Revert commit: 7045806
Closes hotwired/turbo#432
Follow-up to hotwired/turbo#94
Follow-up to hotwired/turbo#31
When a response from within a frame is missing a matching frame, fire
the
turbo:frame-missing
event.There is an existing contract that dictates a request from within a
frame stays within a frame.
However, if an application is interested in reacting to a response
without a frame, dispatch a
turbo:frame-missing
event. The event'starget
is theFrameElement
, and thedetail
contains thefetchResponse:
key. Unless it's canceled (by callingevent.preventDefault()
), Turbo Drive will visit the frame's URL as afull-page navigation.
The event listener is also a good opportunity to change the
<turbo-frame>
element itself to prevent future missing responses.For example, if the reason the frame is missing is access (an expired
session, for example), the call to
visit()
can be made with{ action: "replace" }
to remove the current page from Turbo's page history.