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

Some thoughts about turbo-frame-tags when the redirected render doesn't contain any turbo-frame-tags that match the original #94

Closed
kobaltz opened this issue Jan 8, 2021 · 4 comments

Comments

@kobaltz
Copy link

kobaltz commented Jan 8, 2021

Firstly and perhaps most importantly, thank you so much for Turbo. I really enjoy it!

Let's take a very simple example of a new Rails application with hotwire-rails created. We create a scaffold for products and within the form partial of the products, we wrap the form elements in a turbo_frame_tag 'product'. The expected behavior now is if there are any validation errors, it renders the page with the validation errors. Turbo accomplishes this already.

However, if there are no validation errors and the record persists successfully, then I would expect it to render the display of the show page. However, because there is no turbo-frame-tag on the show page, it doesn't do anything and we still have the form displayed.

I think that this is very unexpected behavior even though things make sense with turbo. I know that this functionality has caused me a few headaches initially and also the community with trying to find proper workarounds.

I'm not the best Javascript person out there, but dabbled around in it a bit, so I would leave any PR to the experts. However, I did pull in the turbo library from turbo-rails into my application to tinker with things and came up with a minor-ish fix.

Within the FrameController class, I modified the loadResponse function. I added the const html which before was simply inside of the fragmentFromHTML, but the important bit is the else statement. It looks like the element is the rendered result from our Rails application and the turbo-frame-tag has been plucked out as a fragment of the original rendered response. So, if no element is found, then that means that the rendered page did not have any turbo-frame-tags which means that our UI will look like it did not perform any action.

My thought here is to replace the body of the current page, with the entire contents of the rendered response in the event that no turbo-frame-tag was found within the response.

  async loadResponse(response) {
    const html = await response.responseHTML
    const fragment = fragmentFromHTML(html);
    const element = await this.extractForeignFrameElement(fragment);
    if (element) {
      await nextAnimationFrame();
      this.loadFrameElement(element);
      this.scrollFrameIntoView(element);
      await nextAnimationFrame();
      this.focusFirstAutofocusableElement();
    } else {
      document.getElementsByTagName("html")[0].innerHTML = html
    }
  }
@kobaltz kobaltz changed the title Some thoughts about turbo-frame-tags when the redirected render doesn't contain any Some thoughts about turbo-frame-tags when the redirected render doesn't contain any turbo-frame-tags that match the original Jan 8, 2021
@sstephenson
Copy link
Contributor

Thanks for opening this issue! What we intend to do when there's no matching frame in the response is to empty out the frame's contents and log a message to the console. Hoping to get that in for the next beta.

@kobaltz
Copy link
Author

kobaltz commented Jan 8, 2021

Thanks for the quick response @sstephenson! I wonder if there could be an option which would default to the functionality as you're describing, but a configuration override which would render the response and update the history. It seems like this would give best of both worlds.

@sstephenson
Copy link
Contributor

sstephenson commented Jan 8, 2021

It's an interesting idea, but I think it's more important to preserve the contract that navigation in a frame stays in the frame unless you explicitly opt out with target="_top" or data-turbo-frame.

Generally we avoid configuration options unless we have no other choice. But I'd be open to adding any special hooks necessary to allow you to implement this outside of Turbo.

@kobaltz
Copy link
Author

kobaltz commented Jan 8, 2021

That's understandable. And I think having some hooks would be sufficient if we also got the responseHTML along with some indication of the element being found or not (the DOM was updated with a new turbo-frame-tag). We could then probably use the turbo:submit-end to load the view and update the history if the event indicates that no changes were made on the page.

seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 14, 2021
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 `url:`
key, and the `response:` key containing:

* `redirected: boolean`
* `responseHTML: string`
* `statusCode: number`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", ({ target, detail: { url, response } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    const visitOptions = response
    Turbo.visit(url, visitOptions)
  }
})

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 14, 2021
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 `url:`
key, and the `response:` key containing:

* `redirected: boolean`
* `responseHTML: string`
* `statusCode: number`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", ({ target, detail: { url, response } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    const visitOptions = response
    Turbo.visit(url, visitOptions)
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 14, 2021
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 `url:`
key, and the `response:` key containing:

* `redirected: boolean`
* `responseHTML: string`
* `statusCode: number`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", ({ target, detail: { url, response } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    const visitOptions = response
    Turbo.visit(url, visitOptions)
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 14, 2021
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 `url:`
key, and the `response:` key containing:

* `redirected: boolean`
* `responseHTML: string`
* `statusCode: number`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", ({ target, detail: { url, response } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    Turbo.visit(url, { response })
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 15, 2021
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. To transform the `FetchResponse` into a `Visit`,
clients can extract:

* `redirected: boolean`
* `statusCode: number`
* `responseHTML: Promise<string>`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", async ({ target, detail: { fetchResponse } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    const { location, redirected, statusCode, responseHTML } = fetchResponse
    const response = { redirected, statusCode, responseHTML: await responseHTML }

    Turbo.visit(location, { response })
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 15, 2021
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. To transform the `FetchResponse` into a `Visit`,
clients can extract:

* `redirected: boolean`
* `statusCode: number`
* `responseHTML: Promise<string>`

Event listeners for `turbo:frame-missing` can forward the `detail`
directly to a `Turbo.visit` call:

```js
addEventListener("turbo:frame-missing", async ({ target, detail: { fetchResponse } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    const { location, redirected, statusCode, responseHTML } = fetchResponse
    const response = { redirected, statusCode, responseHTML: await responseHTML }

    Turbo.visit(location, { response })
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 18, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", async ({ target, detail: { fetchResponse, visit } }) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(target)) {
    visit({ action: "replace" })
  }
})
```

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 18, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", (event) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(event.target)) {
    const { detail: { fetchResponse, visit } } = event

    event.preventDefault()
    visit()
  }
})
```

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.

Similarly, if the reason for the missing frame is particular to the page
referenced by the element's `[src]` attribute, this is an opportunity to
change that attribute (calling `event.target.removeAttribute("src")`,
for example) before navigating away so that re-visiting the page by
navigating backward in the Browser's history doesn't automatically load
the frame and re-trigger another `turbo:frame-missing` event.

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31

cancelable event
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 18, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", (event) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(event.target)) {
    const { detail: { fetchResponse, visit } } = event

    event.preventDefault()
    visit()
  }
})
```

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.

Similarly, if the reason for the missing frame is particular to the page
referenced by the element's `[src]` attribute, this is an opportunity to
change that attribute (calling `event.target.removeAttribute("src")`,
for example) before navigating away so that re-visiting the page by
navigating backward in the Browser's history doesn't automatically load
the frame and re-trigger another `turbo:frame-missing` event.

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 18, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", (event) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(event.target)) {
    const { detail: { fetchResponse, visit } } = event

    event.preventDefault()
    visit()
  }
})
```

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.

Similarly, if the reason for the missing frame is particular to the page
referenced by the element's `[src]` attribute, this is an opportunity to
change that attribute (calling `event.target.removeAttribute("src")`,
for example) before navigating away so that re-visiting the page by
navigating backward in the Browser's history doesn't automatically load
the frame and re-trigger another `turbo:frame-missing` event.

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 18, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", (event) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(event.target)) {
    const { detail: { fetchResponse, visit } } = event

    event.preventDefault()
    visit()
  }
})
```

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.

Similarly, if the reason for the missing frame is particular to the page
referenced by the element's `[src]` attribute, this is an opportunity to
change that attribute (calling `event.target.removeAttribute("src")`,
for example) before navigating away so that re-visiting the page by
navigating backward in the Browser's history doesn't automatically load
the frame and re-trigger another `turbo:frame-missing` event.

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Nov 21, 2021
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.

The `event.detail.visit` key provides handlers with a way to transform
the `fetchResponse` into a `Turbo.visit()` call without any knowledge of
the internal structure or logic necessary to do so. Event listeners for
`turbo:frame-missing` can invoke the `event.detail.visit` directly to
invoke `Turbo.visit()` behind the scenes. The yielded `visit()` function
accepts `Partial<VisitOptions>` as an optional argument:

```js
addEventListener("turbo:frame-missing", (event) => {
  // the details of `shouldRedirectOnMissingFrame(element: FrameElement)`
  // are up to the application to decide
  if (shouldRedirectOnMissingFrame(event.target)) {
    const { detail: { fetchResponse, visit } } = event

    event.preventDefault()
    visit()
  }
})
```

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.

Similarly, if the reason for the missing frame is particular to the page
referenced by the element's `[src]` attribute, this is an opportunity to
change that attribute (calling `event.target.removeAttribute("src")`,
for example) before navigating away so that re-visiting the page by
navigating backward in the Browser's history doesn't automatically load
the frame and re-trigger another `turbo:frame-missing` event.

[contract]: hotwired#94 (comment)
[hotwired#432]: hotwired#432
[hotwired#94]: hotwired#94
[hotwired#31]: hotwired#31
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Aug 1, 2022
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
seanpdoyle added a commit to seanpdoyle/turbo that referenced this issue Aug 1, 2022
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
dhh added a commit that referenced this issue Aug 3, 2022
* Introduce `turbo:frame-missing` event

Closes [#432][]
Follow-up to [#94][]
Follow-up to [#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]: #94 (comment)
[#432]: #432
[#94]: #94
[#31]: #31

* re-run CI

* issue a new request for the full page of content

* Add console warning if a full-page visit is triggered as a result of missing matching frame

Co-authored-by: David Heinemeier Hansson <david@hey.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants