1

I know that I can store the last element on the page and when an user returns I can use an offset to fetch the content from where that user has left off, my question is, is there a way to keep the page loaded with all the dynamic content?

For example on LinkedIn or Twitter, when you go back from a tweet/post the page does not seem to make the requests again, it's an instant transition.

Does that mean you can preserve the entire page with JS somehow and restore it immediately without making requests to the server again ? Or is it some sort of shenanigan where the page does not actually change, so it's just one page app, and all the content gets loaded dynamically ?

Edit: I think Twitter/LinkedIn somehow replaces content on the same page and does not redirect to another page (I'm guessing), But I have 2 separate page.

I will rephrase, and try to explain better.

I have a Infinite scroll page, that loads content in chunks, say I load 10 images at a time staked vertically.

Users scrolls and loads 30 pictures, when you click on a picture you get redirected on another page where you see the picture full screen.

Now users clicks the back button, gets back on the main page, how can I make so the users sees the content from where he left off.

Solutions I've tried.

1 -- I can store the current offset of an image and load from there when the user get's back, but I only load 10 images at a time, if the user click the 11-nth picture, I can still pull from there but it messes with the scroll position because that picture is now first on the page, and the page is scrolled down, to where the 11-nth picture would have been.

2 -- I can store how many pictures have been loaded, so if the user loaded 50 pictures while scrolling when, he gets back and I just load how many pictures there were before the page change, but I think that's not a good idea because loading big amounts of content like that impacts performance.

How Can I show the user the content from where he left of, when returning to the main page, and keeping the scroll position on an infinite scroll page? (I'll give twitter as an example again)

RDU
  • 812
  • 1
  • 9
  • 22
  • Look up cookies and sessions. The information has to be stored on the users browser IF they permit it. – TimBrownlaw Jun 09 '20 at 18:20
  • It's not shenanigan's; it's a single page web application so the content on the page does not change; it just gets hidden and redisplayed when you access the same URL again; the browser is going back to the URL but there's JavaScript running that knows what to display as the "page", preserving any dynamically loaded content; the request doesn't reach out to the server (doesn't have to). Whatever solution you choose for best performance it needs to be client-side (ie JavaScript). – Tom Pimienta Jun 10 '20 at 15:50
  • Giving 200 rep for the question isn't worth it. The question as is is going to be hard to get any more detailed answers than the ones already there. – Alexandre Elshobokshy Jun 12 '20 at 13:37

2 Answers2

1

I would recommend that you use localStorage for this which has pretty good storage capacity.

You are limited to strings in it, so you'll need to convert everything to and from JSON for best results.

What you store is up to you. I would create an object with various properties like current scroll height, last requested index, and an array holding everything that you've pulled from AJAX so far (as well as whatever you created on page load). You might also want to store what page this is on if you are going to use this logic on multiple pages, or just change the key per page. If you share a key, however, you can also completely skip AJAX calls for data that you already have and you consider to be "fresh" by your own business logic.

Below is some sample code. If you press the start button and let it run for a couple of seconds, you'll see the list grow with timestamps. If you then refresh the page, everything will still be there.

First, some HTML to get us working, a button to start and stop as well as the list that we'll be writing to.

<button id="start">Start</button>
<button id="stop">Stop</button>

<ul id="list">

</ul>

And then the JS is next, with inline comments that should hopefully explain everyting:

// This is the interval key, used when stopping the interval code
let iv;

const cache_key = 'my-cache-key';

function stop() {
    window.clearInterval( iv );
}

function start() {
    iv = window.setInterval( tick, 1000 );
}

function makeLi( text ) {
    const li = document.createElement( 'li' );
    li.appendChild( document.createTextNode( text ) );
    return li;
}

// Run once a second
function tick() {
    // Create a timestamp
    const ts = new Date().getTime();

    // Store it to local session
    store( ts );

    // Append to our list
    const ul = document.getElementById( 'list' );
    ul.appendChild( makeLi( ts ) );
}

function store( text ) {
    // See if we have our key
    let items = window.localStorage.getItem( cache_key );

    // Parse it as JSON or set it to an empty array to start
    if ( items ) {
        items = JSON.parse( items );
    } else {
        items = [];
    }

    // Append our current key
    items.push( text );

    // Push it back
    window.localStorage.setItem( cache_key, JSON.stringify( items ) );
}

// One page load, recreate all items
function load() {
    const ul = document.getElementById( 'list' );
    let items = window.localStorage.getItem( cache_key );
    if ( !items ) {
        return;
    }
    items = JSON.parse( items );
    items
        .forEach(
            ( item ) => {
                ul.appendChild( makeLi( item ) )
            }
        );
}

// Click handlers for the button
document.getElementById( 'start' ).addEventListener( 'click', start );
document.getElementById( 'stop' ).addEventListener( 'click', stop );

// Reload anything previously stored on page refresh
window.addEventListener( 'load', load );

As for what you store in local storage, that depends. If your DOM is complex but short, you could possibly store the outerHTML of it, but that's a little bit ugly. Instead, I would store the minimum number of fields that you receive from AJAX that you need to use to create objects.

Also, on whatever you are storing, I would recommend having a property on your object called something like "version", and whenever you introduce a new feature to your AJAX logic increment this manually. That way, if someone comes back to your page with data that no longer makes sense, your app can detect it and throw it away.

This sample app stores a very simple array, but like I said, you'll probably want to store an object and you'll also want to perform validation and sanitization, just like you do in AJAX.

edit

I should also add, you'll want to make sure that you have far-future cache expires on resources like images in order to gain extra site speed from local caching.

From my comment, this site (which is 4 years old) says that 97.6% of people have local storage enabled, so I would absolutely use this since the downgrade is just "only the most current" which is still not a bad experience.

If you open your developer tools on your reference sites, you can inspect the application section for local storage and you'll find a version of what I'm talking about there.

Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • Would it be a bad idea to store the data in mySql ranther than using localStorage, at least just for that session, until the user leaves ? So it would work even if people disable localStorage, I don't know how many users do that though. – RDU Jun 09 '20 at 23:00
  • If you want to be dynamic and fast, this is generally the way to do it. If you store it in MySQL, you will either have to make a fat AJAX request or force the page to not be cached and somehow store user information about "they already read 500 posts so show those". According to this slightly [outdated site](https://blog.yell.com/2016/04/just-many-web-users-disable-cookies-javascript/), 97.6% have localstorage enabled, so I'm pretty certain this is an upgrade feature for almost everyone. – Chris Haas Jun 09 '20 at 23:05
  • Just one more thing that I'm not sure about, what if the user spends a lot of time and loads a lot of content while scrolling, that gets stored and when he comes back, now there's massive html that gets pulled from localStorage on the page, do I need to somehow pull this content in chunks too, or is it fine just loading everything at once ? – RDU Jun 13 '20 at 07:47
  • Just to be clear, I wouldn’t (Generally) recommend storing HTML, but data to make DOM items. That said, you shouldn’t really see too much of a perf issue recreating a large DOM, but you’d also have to test it. Set your images to lazy load, so if they aren’t cached there won’t be a download unless they are in the viewport. – Chris Haas Jun 13 '20 at 14:08
1

This question is too broad, but as it can't be closed while there's a bounty on it I might as well answer with equally broad answer.

  1. Do you really need this at all? Why not open full-sized images in new tabs? Or why not open them without leaving the page? You can use History API if you want the backward/forward functionality. And you'll save all the traffic you can. Also while showing a full-sized image you can allow user to move between full-sized images with arrow keys, and some other cool staff.

  2. About

    but I think that's not a good idea because loading big amounts of content like that impacts performance

    with right caching - not really. Images won't be reloaded... that is of course if you load them through urls and not in some other strange way.

  3. About the title of the question: we should really talk about recreating the state not about restoring it. Because for this:

    Can you preserve the dynamic content of a page that uses ajax, so it gets restored when a users comes back?

    The answer is: "No you can't". Not because it's totally impossible, but because you'll most definitely fail at it. To archive this goal you'll need to

    1. Serialize each and every variable of your app somewhere on each and every change. Including info about dynamic changes to the DOM.
    2. And not everything is easy to serialize: Promises, WeakMaps, Symbols, data with cyclic references, etc.
    3. Next, you'll need to deserialize them back. And it's also can be a challenge. Especially, if between the serialization and deserialization there were some changes on the server-side. (Probably it's easier to just throw everything away and start over)
    4. Also you'll need to decide if it should be done at all. For example if user visits you page a month later - do you really want to show the month old state?
  4. But if we talk about storing some important variable and recreating the state from them, then the answer is: "Yes, it happens all the time".

    There are different ways to store data on the client side (even a DB!) and even more so to store data on the server-size.

    They all good for they own scenarios. It hard to say what is the best way without knowing these scenarios.

    But in this particular case, you need to store only 1 or 2 variables. And using cookies is probably the best choice. Although nowdays you need to show some nagging messages if you use cookies. Because of EU cookie directive. But they a easy to use and if for example you decide to present the user with a fresh state after a month you just need to set expiration date for a cookie, while you'll need to code this logic yourself if you use localStorage.

    And probably there is no need for server-side storage in this apparently not a business site.

x00
  • 13,643
  • 3
  • 16
  • 40