Skip to content
This repository was archived by the owner on Jul 28, 2018. It is now read-only.

history.pushState #363

Open
DohanKim opened this issue Apr 10, 2014 · 17 comments
Open

history.pushState #363

DohanKim opened this issue Apr 10, 2014 · 17 comments

Comments

@DohanKim
Copy link

Sometimes, I need to use history.pushState function independently of Turbolinks.
For example, there is a list of images. And if users click one of the images, I want to show detail view of the image as "modal view" by using javascript (like pinterest). So actually, 'image list view' and 'detail image view' are combined in one page. But I want to separate these into two pages by using history.pushState function so 'detail image view' could have their own URLs (also like pinterest).

Here is the thing. When I use pushState and Turbolinks together, I think pushState function is behave in unintended way because Turbolinks is already using pushState function as its own way, so it seems they crash each other.

Personally, I resolved this issue by putting a function in Turbolinks which do almost same things with 'fetch' function except one thing that the function does not change any part of page and let users could change the page. So users could invoke that function and change view manually when they want to show new page in front of previous page.

Do you think this kind of feature is needed for Turbolinks? If you think it's need, I will polish my codes and make a pull request.

@Burkazoid
Copy link

@DohanKim I am experiencing the same issue and would definitely appreciate seeing the added function. I think such an addition to Turbolinks would be very useful for people who do need to use history.pushState for other purposes which currently conflict.

@markevich
Copy link

Yea. Did you try to use Turbolinks with Angular which use push state for routing? Everything just blows up. So every time we need to write hacks for maintaining turbolinks state in history. This is so awful =(.

We really need some kind of public function for changing history state without breaking turbolinks logic. @DohanKim , please polish and share your code, it may be very helpful for other users.

@AlexRiedler
Copy link

I am using something similar to modal with pushState and would ideally like some way to do this as well. There currently is an issue on History.back() because there is no way to prevent a 'popstate' from propagating through into turbolinks. Even just some way to tell Turbolinks to do a History.back() without handling it would be perfect.

@AlexRiedler
Copy link

I thought a little more about this; It feels like a relatively large undertaking though...

The issue is that window.addEventListener on 'popstate' handlers cannot be prevented; so either we need to be able to hackily 'cancel' it when a popstate occurs and bind earlier then it; or be able to setup our own initialization so we can use our own event binding libraries such as jQuery.

maybe someone has any other ideas? I would consider moving it to use history.js or similar but in a way it is nice cause turbolinks is self-contained.

@javan
Copy link
Contributor

javan commented Feb 11, 2015

Turbolinks adds its own state object with pushState and then checks for that state object onpopstate so in theory you should be able to use them independently without conflict.

I feel like I may not be understanding your issue though. Can you provide a simple example?

@AlexRiedler
Copy link

@javan the issue is that you cannot stop the turbolinks from firing their onpopstate event.

e.g.

  • you have a custom modal that pushes their own state
  • you hit back button (you don't want turbolinks to handle this pop cause the page has not changed)
  • there is no way to stop the propagation to the turbolinks handler, or make it stop since its binding natively (if you bindFirst in the stack of popstate handlers in for say jquery, you could stopImmediatePropagation, and return false).

@javan
Copy link
Contributor

javan commented Feb 11, 2015

If you're using an <a> element to initiate your own pushState, try opting that element out of Turbolinks: https://github.com/rails/turbolinks#opting-out-of-turbolinks

@jgrannas
Copy link

I am having a similar issue. I am updating my page with an ajax response with data-remote on an anchor tag and manually calling history.pushState in the JS response to make the URL match the proper page.

history.pushState({}, '', '<%= request.path %>');

However, this causes the back button to no longer work, i have to manually refresh to get my page changes. I also tried adding data-no-turbolink to the anchor tags but that makes no difference. Is there a way to use turbolinks to update the URL rather than me manually calling pushState? Or a way to force reloads on back/next?

I'm on turbolinks 2.5.3 and rails 4.2.0

@AlexRiedler
Copy link

I worked around this by forking and adding a cancel function to the api, which cancels for one popstate. It's not ideal, but it does the job in my scenario. Really when dealing with pop state you need to be able to control the event stack manually and delegate it as necessary.

@jvenezia
Copy link

Not sure to understand this issue, but mine seems related.
I need to call history.pushState() manually, and the back button does work for those manually added states.
I worded around by visiting the url my self when window.onpopstate is triggered.
It works, but I would prefer to have something to add a Turbolink state my self.

@AlexRiedler
Copy link

@jvenezia its easy to add a turbolink state yourself; just using the visit action (but maybe I am misinterpreting)

@jvenezia
Copy link

@AlexRiedler Actually, I need it to be different from a turbolinks visit. I need to update a section of my page (without reloading everything), and keep the history.

Here's what I did:

window.onpopstate = (event) ->
  if event.state && event.state.isMyCustomState
    Turbolinks.visit(document.URL)

...
history.pushState({isMyCustomState: true}, '', url)
...

It works well, but i'm not sure it is the best way to handle this.

@jvenezia
Copy link

I just realized that it works perfectly using a state similar to turbolink's:

history.pushState({turbolinks: true, url: url}, '', url)

This way, the back event is handled by turbolinks.
Sorry, it may not be related to this issue.

@thomasdavis
Copy link

Thanks @jvenezia I imagine you just saved me a bunch of time!

@Thibaut
Copy link
Collaborator

Thibaut commented Sep 20, 2015

Providing public APIs for doing pushState / replaceState via Turbolinks wouldn't be a bad idea. Feel free to open a PR.

In the meantime you can do what @jvenezia suggested (but keep in mind that this isn't officially supported and may break in the future).

@Thibaut Thibaut closed this as completed Sep 20, 2015
@jaredhales
Copy link

Providing public APIs for doing pushState / replaceState via Turbolinks wouldn't be a bad idea. Feel free to open a PR.

@Thibaut Any reason why this can't be marked as a "Feature Request" and left open?

For now I'll use the solution proposed by @jvenezia but I'd like to replace that in the future if/when someone is able to implement a public api for this.

@agnjunio
Copy link

agnjunio commented Apr 27, 2016

Here`s what I did:

function changeUrl(newUrl, options) {
    if (window.history.state.turbolinks)
        window.history.replaceState(options, document.title, newUrl);
    else
        window.history.pushState(options, document.title, newUrl);
}

It works well
EDIT: ...unless you need to make an a href from the page and go back

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests