-
Notifications
You must be signed in to change notification settings - Fork 432
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
Restoring GET-form state on restoration visits #894
Comments
Hello. What is the state of the form that didn't get restored? I got some similar issues before because JS changes to the next state before the snapshot. What I did was including the controls inside the frame, so for example the active tab is rendered with the rest. Although, sometimes you need to do JS changes that you need to play with using |
@night91 So I whittled down my production example down into a simple form that contains a single radio button group. No additional javascript besides a call to Consistent with what I was seeing before, the url updates, the content inside the frame updates, but upon clicking the back button in the browser, the radio button that triggered the submission remains checked. 🤔 It's as if the turbo page cache is being populated before the advance occurs. So then the restoration visit uses the page cached post form submission instead of pre form submission. I'm trying to familiarize myself with the codebase to better understand the timing of these bits. |
@tonywok the intended behavior I think is to populate the cache before the advance, so it takes a snapshot just before the advance. As the selected radio is checked before the advance, that is why the restoration visit have it checked in the cache. I think the way is to use I don't understand the issue you refer about: |
@night91 Thanks so much for your commentary!
I saw some mention of form reset in the docs. To be clear, by reset you're referring to this, right? If I'm following, this would still leave us in a state where the params don't necessarily match the "form element's default values", right?
I will try this approach. Sounds very promising. As for the comment about Related, was discussing this with a friend and he pointed out how the page snapshot is taking special action on password and select inputs. I've not confirmed this, but it is peculiar that I'm running into this behavior using radio buttons and check boxes 😅 |
@tonywok the reset is not necessary HTMLFormElement.reset(), that may work, but you can also perform some additional actions to actually reset the form, collapse some elements, hide a drop dawn, modal, etc. Disable cache is more for things as flash messages, sort like that, otherwise the restoration visit will show nothing there. When I got a similar issue about tabs (links) loading frames, I solved it, moving the tabs inside the frame. The new active will come with the frame loaded. With radio buttons is tricky because you actually need to prevent the radio to be checked, otherwise the cache will be saved with the new state instead of the previous. |
@night91 I'll try both approaches and report back -- thanks again (fwiw, I was going down the Yeah, with a radio button, preventing it from being checked seems like it'd make it seem to the end-user that they didn't actually check it 😅 |
Not really, because the frame will be rendered quickly with the radio checked. |
@night91 So this was interesting. The select box behaves as I'd expect, but the radio does not. It's like the radio button variant is one page snapshot behind 😅
So I've tried this, and I'm confused by what you mean by "without checking the radio". Wouldn't that result in not submitting the right value for the radio group 😅 |
@tonywok Reading the code they save the form inputs values before the snapshot. Imagine you have the form with inputs and the radio button group, you write something and change the radios, then you submit, the restoration visit show the form saved values. I think it should work the same for the select buy from what you show me, the select value is cached without the new value. I need to do some test later. |
That seems like a good way to phrase it. The restored input has the value that was set when the form was submitted, rather than when that page was actually rendered. This seems like an issue of caching the live DOM properties for the inputs, instead of just the original HTML attributes of the tag. The user has changed the form field before submitting. This deliberately only updates the DOM property, not the tag attribute. When restoring the page, we really only want to restore the original form, rather than the form with the user's ephemeral property changes. It looks like there's already special code for handling turbo/src/core/drive/page_snapshot.ts Lines 26 to 43 in 4593d06
The special behavior for
|
From my understanding (and experience) turbo cache code already cached
All these combined mimic how some browsers (e.g. Chrome) implemented bfcache. @tonywok - there are some possible solutions to work around the bfcaching of a specific form, but it first it would be helpful for you to share the code for the above gif examples? Note: for more background behind turbo and bfcache, you may be interested in this thread: turbolinks/turbolinks#574 |
@tleish Thanks for the response. I'll push up an example repo over lunch. |
I think saving the input values in the snapshot was the intention, in my tests the select also saves the selection. If you want to reset the form, you can do it in the event @tonywok You are getting "the behind" because you have checkbox 1 selected with value 1 visible. You select the checkbox 2, but the cache will save Checkbox 2 and value 1. When you go back, that is what you will see because that was what was saved. I really don't know how to do it with the approach of the form, the click in the checkbox and updating the frame. Because you actually need to select the new checkbox to send the value. |
@tleish I've made a vanilla minimal rails application that reproduces the behavior I was observing. It can be found here https://github.com/tonywok/turbo_form_restore If you have time to run it and do, let me know if you run into any issue. |
It appears there's a bug in turbo where select value cache is not restored in a restoration visits when inside of a turbo-frame. If you remove the turbo-frame, it restores the select from cache. If you do not want bfcache applied to the form elements, you could create a separate controller (or the existing form controller) with the following: connect() {
this.element.reset();
} This resets all form values to the value stored in the HTML, not the DOM. |
Thanks for this, @tleish. That is exactly what I needed. Closing this -- thanks all! |
Hello there, thank you in advance (pun!) and for your work on this library.
I have a form in my application that uses a GET method. It is used for filtering, so I take advantage of turbo to advance the url via
turbo-action
and update a frame with the results using a targetedturbo_frame
.Upon clicking the back button, for the most part, this works as expected. The history pops and I see the previous url and the contents of the frame are the previous contents.
However, the form controls remain in the state at the time of form submission, as opposed to reverting back to the pre-submit state.
As I understand it, when the back button is pressed, a restoration visit occurs, which attempts to display the page from the turbo cache. I can confirm this is the area of my misunderstanding by disabling caching entirely via
<meta name="turbo-cache-control" content="no-cache">
and observing the expected behavior. (In my case this was observing a radio button group revert to its previously checked value).I see the documentation for
turbo:before-cache
. It seems that is designed to give you a chance to modify the DOM before a snapshot is taken. I tried to use this, but the trouble I ran into is that it also fires when doing regular turbo visits.This all seems pretty intentional, so I'm pretty sure this isn't a bug, but I can't seem to find a way to get this to work as I'd expect without the no-cache hammer. If there's interest, I'd love to contribute back at least some documentation on how to approach this problem.
Happy to provide a minimal reproduction if that's helpful.
Update: I've made a repository that reproduces the observed behavior here
The text was updated successfully, but these errors were encountered: