How to transfer scrolls with turbines?

It is sometimes desirable to maintain scroll positions between page visits.

Turbolinks resets the scroll position after loading data.

How to disable it for certain items?

+7
source share
4 answers

Use the following javascript to continue scrolling. I created a selector that matches all elements with the turbolinks-disable-scroll class. Before loading, the script saves the scroll position and after loading loads the saved positions.

 // persist scrolls // pirated from https://github.com/turbolinks/turbolinks-classic/issues/205 var elementsWithPersistentScrolls, persistentScrollsPositions; elementsWithPersistentScrolls = ['.turbolinks-disable-scroll']; persistentScrollsPositions = {}; $(document).on('turbolinks:before-visit', function() { var i, len, results, selector; persistentScrollsPositions = {}; results = []; for (i = 0, len = elementsWithPersistentScrolls.length; i < len; i++) { selector = elementsWithPersistentScrolls[i]; results.push(persistentScrollsPositions[selector] = $(selector).scrollTop()); } return results; }); $(document).on('turbolinks:load', function() { var results, scrollTop, selector; results = []; for (selector in persistentScrollsPositions) { scrollTop = persistentScrollsPositions[selector]; results.push($(selector).scrollTop(scrollTop)); } return results; }); 
+2
source

My solution in ES6:

 const turbolinksPersistScroll = () => { const persistScrollDataAttribute = 'turbolinks-persist-scroll' let scrollPosition = null let enabled = false document.addEventListener('turbolinks:before-visit', (event) => { if (enabled) scrollPosition = window.scrollY else scrollPosition = null enabled = false }) document.addEventListener('turbolinks:load', (event) => { const elements = document.querySelectorAll('[data-${persistScrollDataAttribute}="true"]') for (let i = 0; i < elements.length; i++) { elements[i].addEventListener('click', () => { enabled = true }) } if (scrollPosition) window.scrollTo(0, scrollPosition) }) } turbolinksPersistScroll() 

And add data-turbolinks-persist-scroll=true to your links for the links you want to keep in the scrollbar position.

<a href="..." data-turbolinks-persist-scroll=true>Link</a>

This works for me, also with link_to remote: true .

+2
source

There seem to be two approaches to this problem.

  • Keep selected items (@ vedant1811 answer)
  • Keep body scroll for selected links.

The second approach is the one I was looking for and could not find anywhere, so I will provide my answer to this question.

The solution here is very similar to the solution of the first approach, but perhaps a little easier. The idea is to capture the current scroll position of the body when an element is clicked, and then scroll to that position after the page loads:

Javascript

 Turbolinks.scroll = {} $(document).on('click', '[data-turbolinks-scroll=false]', function(e){ Turbolinks.scroll['top'] = $('body').scrollTop(); }) $(document).on('page:load', function() { if (Turbolinks.scroll['top']) { $('body').scrollTop(Turbolinks.scroll['top']); } Turbolinks.scroll = {}; }); 

Markup

 <a href='/' data-turbolinks-scroll='false'>Scroll preserving link</a> 

I use the scroll attribute for the Turbolinks object to store my scroll position when I click the [data-turbolinks-scroll=false] link, and then after scrolling the page, I clear this attribute.

It’s important that you clear the attribute ( Turbolinks.scroll = {} ), otherwise, subsequent clicks on non-anchored links will continue to scroll to the same position.

Note: depending on the specific html and body style, you may need to scroll scroll off from both. An example of how this can be accomplished:

 Turbolinks.scroll = {}; $(document).on('click', '[data-turbolinks-scroll=false]', function (e) { Turbolinks.scroll['top'] = { html: $("html").scrollTop(), body: $("body").scrollTop() } }); $(document).on('turbolinks:load', function() { if (Turbolinks.scroll['top']) { $('html').scrollTop(Turbolinks.scroll['top']['html']); $('body').scrollTop(Turbolinks.scroll['top']['body']); } Turbolinks.scroll = {}; }); 
+1
source

I noticed that sometimes the scroll goes up, and then only down. This version prevents this behavior:

 const persistScrollDataAttribute = 'turbolinks-persist-scroll'; let scrollPosition = null; const turbolinksPersistScroll = () => { if (scrollPosition) { window.scrollTo(0, scrollPosition); scrollPosition = null; } const elements = document.querySelectorAll('[data-${persistScrollDataAttribute}="true"]') for (let i = 0; i < elements.length; i++) { elements[i].addEventListener('click', () => { document.addEventListener("turbolinks:before-render", () => { scrollPosition = window.scrollY; }, {once: true}) }) } } document.addEventListener('turbolinks:load', turbolinksPersistScroll); document.addEventListener('turbolinks:render', turbolinksPersistScroll); 
+1
source