-
Notifications
You must be signed in to change notification settings - Fork 434
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
Unable to manage history state programmatically (stream response) #792
Comments
Ok, the exception comes from the incorrect BrowserSync setup. This config partially solves the issue: snippetOptions: {
rule: {
match: /<\/head>/i,
fn: function (snippet, match) {
return snippet + match;
},
},
}, Credits: https://blog.aidistan.site/2022/10/08/browser-sync-for-turbo-rails.html However, the problem still partially exists. Now, when I'm pushing the navigation state this way: Turbo.StreamActions.my_push_state = function () {
// const url = new URL(this.getAttribute("url"));
const url = this.getAttribute("url");
history.pushState(history.state, "", url);
Turbo.navigator.history.push(url);
// Turbo.navigator.history.push(url, history.state.turbo.restorationIdentifier);
// console.log("my_push_state", url);
}; It creates 2 entries in a browser history stack instead of one. When I click |
If you are using Turbo's navigator then you won't have to perform browser's |
Well, unfortunately it doesn't work otherwise. I need to dig into sources to see what
If that is not possible I'd have to respond with redirect from my POST form submission then, so Turbo will do all required operations itself. However, that would add additional network round trip that I would like to avoid. |
Apparently, this Redirecting After a Form Submission doesn't do what I expect. I have a GET form with the action target set as I guess I have to make |
I think I've managed to solve this case by doing the following Custom Stream ActionTurbo.StreamActions.my_push_state = function () {
const url = this.getAttribute("url");
const state = {
turbo_stream_history: true,
};
history.replaceState(state, "", window.location.href);
history.pushState(state, "", url);
}; What it does is makes sure that the current URL and the new URL are marked for manual visits if navigated back/forward later. global
|
I've managed to accomplish the cache issue by slightly changing custom stream action: Turbo.StreamActions.my_push_state = function () {
const url = this.getAttribute("url");
const state = {
turbo_stream_history: true,
};
Turbo.cache.exemptPageFromPreview();
history.replaceState(state, "", window.location.href);
history.pushState(state, "", url);
};
It is also probably possible to simply stop caching in stream response by running |
While this does update the URL, it doesn't seem to store the state in the history. e.g, pressing back in browser history does not restore the previous state. Nothing this issue is quite old, do you have a solution for this? |
@trsteel88 I left this as-is since in my particular use-case this was a desired behaviour. |
@trsteel88 in that case you would need to make the "state" part of the actual URL string. You can utilize const url = window.location
const params = new URLSearchParams(url.search)
params.set("turbo_stream_history", true)
url.search = params
window.history.pushState({}, "", url); |
@marcoroth, the URL is updating. However, when navigating back from the browser, the state of the page isn't being replaced to what it was before the URL was changed. e.g. I'm on /page with a GET form with a query value. If I type "H", wait, url changes to /page?query=H Then type, "He", wait, url changes to /page?query=He When I press back, I expect that form input to change back to "H" |
@trsteel88 Trying to get the same behavior you're describing. Were you ever able to get this working? |
@trsteel88 Potential solution: render Example scenario: If we set up our turbo-frame with <%= turbo_frame_tag :products, data: {turbo_action: :advance} do %>
<%= turbo_stream.replace :sidebar do %>
<% @categories.each do |category| %>
<%= link_to category.name, products_path(filters: params[:filters]) %>
<% end %>
<% end %>
<!-- pseudo-code -->
<%= form_for :filters, method: :get, url: products_path do %>
<select-input-that-sends params[filters][color]>
<select-input-that-sends params[filters][size]>
<%= submit_tag 'Filter' %>
<% end %>
<div>
<!-- products HTML here -->
</div>
<% end %> This will:
End result is that all our state is captured in the URL, the user does not lose their scroll position, and browser back/forward arrows worked as expected (including working with Turbo's caching, so that you get instantaneous updates when navigating forward/back). This works because |
@jeffdlange that is an interesting solution. So, to be clear, the logic is the following:
? Can you please provide a sample response from your form? |
@pySilver Whoops, I made a mistake in my example. The sidebar links should include an appropriate data-turbo-frame attr look like this: <!-- sidebar links should target our :products turbo-frame -->
<%= link_to category.name, products_path(filters: params[:filters]), data: {turbo_frame: :products} %> The above link just hits our |
@pySilver The request would look something like:
And the response would be our Let me know if that makes sense. |
@trsteel88 did you manage to make it work? I got back to this and yep - it's easy to replace url but it's probably impossible to "cache" new state... |
OK. Doing this directly like this |
Cache is not saved so when we return to the previews page, the page is not reloaded |
It seems like this issue was supposed to be fixed with the addition of |
I tried |
@nfacciolo Wait, really? Let me state what I tried which isn't working. Maybe you've set it up differently? In essence I have:
When I click a link in the conversations-sidebar, it's output is properly redirected to the message frame. As I watch chrome inspector, the whole Then I try adding I want the frame to update and the URL/browser history to update. Did you get that working? (I only got it working with pySilver's hack for manually updating pushState and Turbo cache, but I'd rather not use this hack) |
@krschacht Yes, you aren't the only one with this issue. Once you get into more complex scenarios, especially ones involving the URL and back/forward buttons, Hotwire's tools are not yet robust enough out-of-the-box to handle them (I say this as a huge hotwire fan). On our project, we have a sidebar that loads via turbo frame, and we want the URL to advance when the sidebar loads (similar to the setup you described in your project). We've only been able to accomplish this via workarounds with custom JS, and it still is not as smooth/polished as we would like. We've accomplished it by having links-to-the-sidebar literally carrying a url param called Please update if you find any simpler solutions, but this it's the best our team has come up with so far. |
Hey everyone, after I confirmed that Details over on this issue: #1156 |
In #167 (comment) @seanpdoyle said:
I wanted to share one straightforward use case where my old team needed
We had a similar situation but wanted to avoid a redirect, so we implemented a custom stream action to <turbo-stream action="history" target="replaceState">
<template>https://example.com/thing/new-name</template>
</turbo-stream> Using Following from #1240, I would propose instead: <turbo-stream action="history" method="pushState" url="https://example.com/thing/new-name" />
<turbo-stream action="history" method="replaceState" url="https://example.com/thing/new-name" /> With an optional It would be trivial to support the other |
Hey everyone, Turbo streams aren't intended to update a visit, originally they are only intended to perform more complex dom operations in a response. Closing this for now |
My use case is fairly simple. I have a list of products and a filter POST form. Whenever a user triggers form submit I receive a stream response that updates the product list and current page URL to something shareable. Filter form itself is contained in a
<turbo-frame>
if that matters.My goal is to update the page URL every time user makes changes to a filter form while letting them go back in history and "unapply" filters by simply pressing the
Back
button in a browser.Here is my custom stream action:
And here is the stream response from the server after the filter form is submitted:
I cannot make it work. When the
Back
button is pressed the following error appears in a console:The text was updated successfully, but these errors were encountered: