igor-alexandrov / wiselinks

If Turbolinks are not enough for you. Wiselinks makes your application work faster.
MIT License
724 stars 89 forks source link

Remembering scroll position on pages #56

Open amnesia7 opened 10 years ago

amnesia7 commented 10 years ago

Is it possible for wiselinks to remember the scroll position for each page?

I have an ajax application that has a list of results. When you click on a result wiselinks updates the page content to show the details.

If I scroll down the list and then click a result to go to the details page I am currently using the following to return to the top of the page:

$("html, body").animate({ scrollTop: 0 }, 0);

I am also using this for when I press back to go back to the list page but I'd like the application to associate a scroll position with each url so that the page returns to the scroll position the user was at when they left that page.

If I press back without the scrollTop code shown above it looks like it tries to scroll down to where I was on the list view but it does that before the list view content reloads so it can only scroll down a little bit (because of the small amount of content on the details view) and then the list view content shows.

If I add a load of extra text to the details view to make the page as long as the list view then when I press back from the details view it jumps down the details page and then reloads the list view content and the page is then scrolled to the correct position.

Is it possible to remember the scroll position on each page bearing in mind that my application is paginated as well so it isn't just a case of remembering scroll position for one page but any number of them?

I'd like navigating to new pages to scroll to the top of the page but press the back and forward buttons to navigate to the position the user was at when they were on that page.

Is there a way to capture the position the browser is trying to scroll to so that it can be re-attempted once the page content has been updated?

Is it viable or should I just scroll the page to the top?....not the best user experience.

Maybe something like this plugin does: http://mrcoles.com/blog/scroll-sneak-maintain-position-between-page-loads/ http://mrcoles.com/scroll-sneak/

Thanks

igor-alexandrov commented 10 years ago

I think that I will store scroll position for each state and then you will be able to use it when you click "Back" button. But logic for new pages should completely stay in you application. This is how I do it:

 $(document).on('click', 'a[data-scroll=true]', 'a[data-scroll-to=true]'
      (event) ->
        if $(this).data('scroll')
          Wiselinks.scroll = true
    )

$(document).off('page:always').on('page:always'
  (event, $target, status, state) ->
    if Wiselinks.scroll
      $('html, body').animate
        scrollTop: 0
        250

      Wiselinks.scroll = false
)
amnesia7 commented 10 years ago

What if you did a search using a form, scrolled down to the bottom of the page and there was another search form at the bottom to do a different search (like Google used to have). Would your code not need to allow for going back through pages where forms had been submitted as well as links clicked? Or what if there was a different form to submit further down the page for some other reason that used wiselinks. It may not be necessary, I'm just trying to think of possibilities. I don't need it to allow for form submissions in my case because the form is at the top of the page anyway so the user would have to scroll to the top to fill it in again anyway.

It might be worth being able to set the scroll speed in case some people want to just jump straight to the position rather than seeing the page scroll at 250 or just setting it as 0 because a browser doesn't scroll down to where you were on the previous page when you click back, it just jumps straight to the position. Also, should scrollTop: 0 not be the position to scroll to instead based on what gets stored rather than 0?

Col

amnesia7 commented 10 years ago

Hi @igor-alexandrov, I was just wondering if you'd managed to make any progress with this or not.

Col

mjrk commented 9 years ago

As referenced above, we, too, had an issue with the scroll positions and solved it by storing them in the history state object. Just have a look at the merged pull request. Unfortunately, we could not backup the scroll positions using the callbacks - during the click and loading events the state data is replaced by library internals. Furthermore we noticed that under certain circumstances, the click callback on the anchor may be triggered after the loading event.

amnesia7 commented 9 years ago

@mjrk Did you do something like this: http://stackoverflow.com/a/16732655/1116573 Should maintaining the scroll position really be something that the history js plugin should be resolving rather than wiselinks?

mjrk commented 9 years ago

We did something similar:

originalLoad = window._Wiselinks.Page.prototype.load
window._Wiselinks.Page.prototype.load = (url, target, render = 'template') ->
  stateData = History.getState().data || {}
  stateData.scrollX = window.scrollX
  stateData.scrollY = window.scrollY
  History.replaceState(stateData, document.title, document.location.href);
  originalLoad.apply(this, arguments)

(scrollTop is set as given by igor-alexandrov.) I tried several possibilities to track the scroll positions but this resulted to be the only working one. Keep in mind that with wiselinks, first the history is set to the previous state by the back-button (and scrolled), THEN the content is loaded. Going backwards to a previous state with a higher (browser-) scrollY then the current window height results in wrong/cutted values. So we have to use the above values in the page:always callback to correct this. Besides, the solutions works with forward, too.

However, it would be cool if it was possible to use a callback to set the scroll values.

Apart from this, for now Wiselinks could nicely solve this using History.js, but in general I think the JavaScript History API should basically track scroll positions in its state (not hacking with state data). If this answers your question.

mjrk commented 9 years ago

Please note, we also had to avoid reloading the page (triggered by statechanged), see https://github.com/fairmondo/fairmondo/commit/daf01b4a58d0f0af97a6e2b2e4525526b65f0a96