I have a page that the user can modify. All modifications are performed using JQuery, and also sent to the server, so that a full reload will produce the modified page too.
This works fine in Firefox 11 / Chrome on Windows: even if the user navigates somewhere else and then uses the "Back" button, they get the page with their latest edits.
However, if I now embed Google Maps onto the page, the Back button stops working: it takes the user to the page how it was before all their edits. This page doesn’t even exist anymore except in browser’s cache, and yet it gets displayed.
I’ve put together a simple testcase here that shows this behaviour.
What gives? How can I fix this? The perfect solution would just allow the browser to go Back without reloading the page, like it would do normally.
P.S. Apparently the "working" example doesn’t actually work in Chrome on OSX either. How can I work around the browser’s insistence on going back to a stale version of the page?
Bug reports describing this behaviour: Firefox
Bounty: Firefox and Chrome on Windows exhibit both behaviours (going back to the modified DOM in one case, but unmodified in another). Is there a spec describing what the browser should do? Are there bugs filed to change this one way or another? Does this issue have a common name that I can google?
I’m considering a solution whereby I update a hidden element via JavaScript, and then check if the update is still there. If so, the "Back" button restored up-to-date DOM, and nothing else needs to be done. If not, the browser restored outdated DOM, and I can just force a page reload, as unpleasant as that is. Any comments on this approach are also welcome.
Note: the real website has more editable controls than that, and one of them is a freeform text area. I would like the proposed solutions to work even if the user has just added several paragraphs of text. That kind of thing can’t be appended to the URL after the #
, for example.
Embedding Google Maps into the page disables the bfcache (I'll use the Mozilla term for lack of a standard one) because the maps page loaded in an <iframe>
uses an unload
listener.
The possible reasons for a page not being cached for fast back navigation in Firefox are listed on MDN: Using Firefox 1.5 caching. Your problem is listed as "the top-level page contains frames that are not cacheable", which is confusing, I'll try to clarify it later. (Other browsers probably use similar heuristics, since these rules were developed to avoid breaking existing content - see also this answer, it has some links.)
The correct way to fix this would be to befriend someone at Google and then nag them until they remove the onunload
listener at least from maps' embedded pages.
In general you shouldn't ever rely on bfcache working or not working for a particular page. It's just an optimization for the common case. Since it's an optimization, it could be disabled, for example when the system is low on memory. It also won't work if the user restarts the browser before going back, or closes the tab and picks 'undo close tab', as you noted in the bug.
You should either restore the page's state from JS or mark the page as not cacheable (using an HTTP header). The former results in a better user experience, of course. @Adam Gent's suggestion looks correct, I'll have to check what Firefox problem he refers to.
The reason bfcache works this way is:
onunload
handlers in a page on the basis that the user might return to the page and they'd like to cache it, the authors would complain.The reason the page is still loaded from the (disk) cache when you hit "back" is that presumably you specified that the content you sent to the browser can be cached. The browser has no way to know that you update the page on the server in parallel with making the DOM changes to it.
[edit]I'll elaborate on the "mark the page as not cacheable" idea above. To make web browser cache work for, and not against you, it's important to remember that HTTP is a protocol for retrieving resources. For example, the HTML page identified by the URL http://bbb.akshell.com/broken is a resource. When you serve a resource over HTTP you specify how long the browser's copy of the resource will be valid (i.e. matching the canonical version of the resource on the server).
When, as in your testcase, the resource is an HTML page with the item selected by the user marked up in a special way, the resource may change at any time (every time the user changes the selection). This means that the honest HTTP response when serving this resource would be "don't cache, may change at any time". The browser would then reload the page from the server every time it needs to load the page -- correct behavior, but at the cost of slowness for the user.
An alternative approach, appropriate for things like switching between multiple in-page tabs would be to associate each selection with its own URL. A page with two tabs would correspond to two resources (and two URLs) -- one for each tab. Both resources could be (HTTP-)cached by the browser. Changing the URL and the page's content could be implemented without the roundtrip to the server via pushState.
Another approach, which seems more applicable to your case, in which you save the user's input on the server: separate the app UI and the user's data into different resources (i.e. a static (HTTP-)cacheable HTML page with JS, loading the user data from a separate non-cacheable URL). Request the user data and update the UI on load.[/edit]
If you don't care about old browsers you could use a combination of local storage and pushstate.
Using @lucian.pantelimon 's solution + pushstate + localstorage should get you what you want.
<script>
window.addEventListener("popstate", function(e) {
alert("hello"); // do my restoration from localstorage.
});
</script>
@TimWi is right that if the browser doesn't fire an event your kind of "up shit creek".
One thing you might want to investigate is a truly gross hack of a frameset (ala reddit/google images/linkedin article style).
EDIT: Looks like the pushstate events don't get fired off when the back button is pressed on a remote site back to your site.
EDIT 2: It looks like my firefox v 10.0 has problems with pushstate. It works fine in chrome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With