Skip to content

Turbo Frame with promoted navigation caching too early #472

@willcosgrove

Description

@willcosgrove

Hi, I think I've stumbled on an issue with the new feature of allowing a Turbo Frame to drive navigation. It appears that the page is being cached earlier than it does when a Turbo Frame is not driving navigation.

I have a video recorded that shows 3 UI bugs that I think are all explained by this.

CleanShot.2021-11-24.at.13.57.00-converted.2.mp4

So everything visible in the window is in a Turbo Frame (there is UI above scrolled out of view that is not in the Turbo Frame). There is a form that encompasses all the filters in the dropdowns. The form is doing a GET request to load new results with the applied filters. Here are the 3 UI bugs to look for:

  1. The date dropdown has a stimulus controller that, upon connect() instantiates a Litepicker, and upon disconnect() destroys the litepicker, removing its DOM. After restoring the initial page visit, there are two sets of Litepicker DOM in the dropdown. This indicates that a snapshot was taken before disconnect() was called.
  2. The button in the Carrier dropdown gets disabled by Turbo and there is some disable-specific text inside the button. After restoring the initial page visit, the button remains disabled. This indicates to me that the snapshot was taken before Turbo re-enabled the button.
  3. There is a Stimulus controller that wraps the filter form that is in charge of resetting the state of the inputs when the dropdown closes, so if the user checks a box and closes the dropdown without clicking "Apply" the checkbox will revert to its initial state. This stimulus controller adds a listener to document for turbo:before-cache that resets the form. But after restoring the initial page visit, the checkbox is still checked. It doesn't get unchecked until the dropdown is opened, and then closed. So the snapshot seems to be happening before turbo:before-cache gets called.

Here's the abbreviated markup of the Turbo Frame

turbo-frame#manifests data-turbo-action="advance" autoscroll=true data-autoscroll-block="start"
  .pb-3.sm:flex.sm:items-center.sm:justify-between
    .flex-1
      = render 'filters'
  / ...

And because it is the smallest controller to include for an example, here is that reset controller:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["reset"]

  connect() {
    document.addEventListener("turbo:before-cache", this.reset)
  }

  disconnect() {
    document.removeEventListener("turbo:before-cache", this.reset)
    this.reset()
  }

  reset = () => {
    if (this.element.reset) {
      this.element.reset()
    }
    for (let target of this.resetTargets) { target.reset() }
  }
}

Let me know if there's any other info I can provide!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions