49

It's amazing, I constantly see this working in other sites but never in sites that I'm working on.

I'm bringing in new content with ajax, I know about history.js and the History API, I do not want to change the URL, just have the browser cache the new HTML content so when a user leaves the page and comes back using the back button, it still has the updated HTML.

I see this working all the time in other sites without URL changes or using the hash #.
Is there a trick to get it to work or is it randomly decided by the browser?
If I don't want to use the URL to have this information, is there an easy alternative?

Madd0g
  • 3,841
  • 5
  • 37
  • 59
  • What about saving the "status" of the page in a cookie ? For example the client has clicked to show the login box, then you save that action in a cookie "login=1" for example, and whenever the client comes back, you use javascript to read the cookie and show the login. Although I don't think this is the "best" solution since there may be too many "options" to take care of. – HamZa May 10 '13 at 07:37
  • 2
    yes, cookies and session and localstorage, all good ways of saving the state, like parameters, to be reloaded. But I see other sites working without that. They don't have any visual delay when I hit the back button even though the entire page was built with ajax. how do *they* do it? – Madd0g May 10 '13 at 07:53
  • Maybe they build the page _before_ onload which should be when the browser caches the HTML. – A.M.K May 10 '13 at 15:35
  • Some browsers have a "Back-Forward Cache"/"Fast History Navigation"/"Page Cache" feature, which is applied to website based on some conditions, see https://webkit.org/blog/427/webkit-page-cache-i-the-basics/ – 4esn0k May 03 '20 at 08:23

5 Answers5

42

For about a decade and half now, I have been using two tricks that I once discovered by painful trial and error: Input field values - especially 'hidden' ones - are preserved in the browser's history along with the URL - AND - the onLoad event is called when returning to the page by the back (or forward) buttons.

This means that you can store as much 'state' as you like - in hidden fields (remember to put them in a form), and then 'redo' the changes on 'onLoad'. I usually make the 'render' part a separate function... In other words, at the time that the dynamicness is occurring, I first write to the hidden fields - then call the render function. Then I gather together all the various render functions for the various bits of dynamicness and call them from the onLoad.

I would stress that I have never gone hunting for this in any manuals - so cannot offer any assurances - but I have been using it reliably for a good while (since Netscape!!!) It works with 'many' browsers (all the IEs, chrome, FF - but as for the others, I've never tried.)

If anyone has a more 'correct' - and less tedious - way, I for one, will be very glad to hear about it. But this does seem to do the trick.

Groover
  • 436
  • 4
  • 2
  • 3
    hey Groover, thanks for the reply, I understand how it's done manually (i.e. save the state 'parameters' and then reload when the user gets back to the page). The thing is, I see on many ajax sites (with firefox as stated in other comments), the HTML is still there when I press back and there's no need to reload at all. I would love to understand how that's done. – Madd0g Jun 10 '13 at 16:40
  • You and me too... :) I wonder how/if the technique that you are after, works with browsers other than FF. I often do work for government agencies - who are often standardized to old IE browsers - some are still on IE6 (though starting to be rarer) - but IE7 will be around a while longer... Anyway, I shall be watching with great interest. Thanks for posing the question. – Groover Jun 12 '13 at 13:59
  • 2
    On re-reading your reply, I would further note that the technique I described does not require an actual server trip to 'reload' the page - or any part of it - or modify the URL etc - the effect is that when you press the back button to return to the page, all of the dynamic changes are magically in place the first time you see the page - whether put there in the first place by ajax - or by simply, say, summing a column of figures. Forgive me if this was already understood. :) – Groover Jun 12 '13 at 14:12
  • wait wait, I may have misinterpreted your answer, do you have a URL which uses this method successfully? It sounds interesting but before trying to achieve it myself, I thought I'd ask for an example, if you have something. Thanks! | EDIT: everything has to happen before onload for this to work? Then it shouldn't work for paging (+things that happen after onload)? – Madd0g Jun 12 '13 at 21:18
  • never mind! I understand what you mean, of course the form fields are saved! with autocomplete=on this will even survive a refresh, maybe. Wow, very smart, how do I give you more points lol – Madd0g Jun 13 '13 at 00:25
  • You must know that it doesn't work with Cache-control: 'max-age=0, private, must-revalidate' – Dmitry Polushkin Aug 20 '14 at 18:52
  • Kinda strange, this was working 100% last night on FF and now the input fields are not being remembered. Testing on Chrome works like a charm! Playing with 'Cache-Control' yields no difference on FF... Looks like I will just be using Chrome now. – Brad G Jul 12 '15 at 17:14
  • Unfortunately this solution does not work on Safari iOS – squareOne Dec 16 '15 at 21:48
  • Solution no longer works in latest browsers :( Welcome to 2018 – Carl Mar 02 '18 at 06:26
9

Author of RES here, found your question in /r/javascript

Apparently, Firefox recently added functionality to do this on its own, but there's no "good" way to do this when the browser doesn't do it for you.

What RES used to do is add a #page=n marker where n was your page number. That way, on pageload, RES knows you must've come from the back button if there's already a location.hash -- unfortunately, this particular behavior borked up ctrl-f find in both Firefox and Chrome when a find caused you to scroll to another page (page = n+1), because a hashchange would close the find dialog which annoyed users...

So now RES does some ugly and imperfect gymnastics to guess whether or not you arrived at the page via the back button. Any time it loads a new page, it saves that number in sessionStorage (like localStorage, but local to the tab), and upon showing up via the back button it fires off a request for that page number.

However: recently I tested in FF and Chrome and it seems that hash changes no longer "cancel" the ctrl-f find dialog, so my suggestion would be that you use that. Upon pageload, if there's a hash present, load the relevant data determined by that hash.

You can, if you want to get really crazy, store the actual HTML content in localStorage and reload it on pageload via back button as well. This might not be the most efficient way of doing things, and would almost certainly cause conflicts with javascript that relies on the DOM, though, so tread with caution!

The "best" solution really depends on what exactly your site is doing / what that content looks / behaves like.

honestbleeps
  • 388
  • 5
  • 12
  • thanks for the reply, very interesting to learn the history. Just like NER in RES, my site just loads new pages of content inline, instead of using traditional paging. Like reddit, the pages themselves don't really stand on their own, so updating the url (thus allowing users to copy the permalink) would just cause confusion if the url gets shared and I wanted to avoid it. But it looks like that's a no go. It's not a REAL requirement anyway, just something I hoped to avoid. thanks – Madd0g May 11 '13 at 20:17
  • I wish I had a better answer for this, other than " there's no "good" way to do this when the browser doesn't do it for you.".. I guess I'll never find out why it works on reddit and not on my sites. Thanks anyway – Madd0g May 16 '13 at 12:45
  • so far as I understand it, only FF will save NER's state on Reddit. are you saying you see Chrome save it too? – honestbleeps May 16 '13 at 16:34
  • I'm not a regular user, but I tested a couple of times in chrome, it doesn't work. It does wonders on firefox though. I've seen in other sites too, they change the URL after the ajax call just like NER used to, and if you leave the page and come back the modified HTML is still there, no reloading – Madd0g May 16 '13 at 19:09
  • yeah, when they change the URL after the ajax call, that's the HTML5 pushState / popState stuff. Without a URL change, you're kind of out of luck, because all browsers (except apparently Firefox as of recent versions) start the page "as it was before any javascript loaded", for the most part. – honestbleeps May 17 '13 at 03:05
1

You can achieve your goal using History.js like this:

function manageHistory(data){

    var History = window.History;
    if ( !History.enabled ) { return false; }        
    History.replaceState({myData: data}, null);
}

$('select.select').change(function(e) { // I am using select tag here to give an example of an HTML action triggerer

    e.preventDefault(); 

    // get data from your select tag

    manageHistory( data)


});

History.Adapter.bind(window, 'statechange', function() { 
    var State = History.getState();

    // Launch the ajax call and update DOM using State.data.myData
});

According documentation about History on Mozilla site, the PushState third parameter is:

URL — ....... This parameter is optional; if it isn't specified, it's set to the document's current URL.

likeitlikeit
  • 5,563
  • 5
  • 42
  • 56
Adib Aroui
  • 4,981
  • 5
  • 42
  • 94
  • thanks, I know how to do it, I've done it with the history.js plugin, but all it does is save the page scroll position at the time of the ajax call. I've tried pushState and replaceState. In both cases the html I've created after page load disappeared when I used the back button – Madd0g May 11 '13 at 05:20
0

I think that reason can be that other webpages uses some back-end servers that provide session.

If you are building static html/js page there is no such session and page just reloads.

You can use cookies to achieve what you want.

el vis
  • 1,302
  • 2
  • 16
  • 32
  • unless they hold pages and pages of html in localstorage, I can't see how it's possible to restore all that without any redrawing, it's instantaneous. Holding just the parameters of the last page in memory and calling it with ajax would definitely make some visible changes and will take more time – Madd0g May 10 '13 at 11:56
0

Local storage is one way, another way is server side persistence.

When the HTML is edited / created / some property is changed on the client side, you need to sync the state change of your page with webstorage or a database via a restful api (or something comparable).

When you return to the page - the page can retrieve stored info from local storage... If you're using server-side persistence, you'll need to use it in conjunction with a session cookie to retrieve the user's state changes - which can then be loaded from the server.

1nfiniti
  • 2,032
  • 14
  • 19
  • this doesn't work at least in chrome. it seems like the browser also caches the ajax get message even though the caching headers are set to no cache. – Roey Oct 10 '17 at 20:57