Preserve Dynamically Changed HTML on Back Button

Preserve dynamically changed HTML on back button

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.

Preserve dynamically changed select values when back button clicked

Because the data is dynamically loaded, the browser will not be able to repopulate the previously selected entries when the user goes back to the previous page.

I suggest you make use of the browser's localStorage to store the latest selections and retrieve them when the user goes back. To accomplish that it's as simple as setting a new variable to the localStorage object and later retrieving it like so:

localStorage.make = "BMW";

alert(localStorage.make);

Also here's a more useful example:

select = document.getElementById("make");

if (localStorage.make) {
select.options[localStorage.make].selected = true;
}

How to implement back button to dynamically generated html?

Here is my solution (coffeescript):

class window.Explore
cached_pages = {}

preserve: (url)=>
current_position = window.pageYOffset || document.documentElement.scollTop || 0

cached_pages[url] =
position: current_position

clean: =>
cached_pages = {}

scroll_back: (url)=>
if cached_pages[url]
$('body').scrollTop cached_pages[url].position

window.cached_explore = new Explore()

window.prev_state = undefined
window.current_state = undefined

$ ->
History = window.History
if !History.enabled
return false

History.Adapter.bind window, "statechange", =>
# store previous history state
window.prev_state = window.current_state
window.current_state = History.getState()
# preserve each page position before leaving
if window.prev_state and window.prev_state.hash
window.cached_explore.preserve(window.prev_state.hash)

place_match = location.pathname.match(/\/place\/(.*)/)

# place page
if place_match
# retrieve place
window.retrieve_place place_match[1], window.search_query, (err, place_dto) ->
# render place page
window.show_place_popup place_dto

# explore places page
else if location.pathname is '' or location.pathname is '/'
# check if a page was already opened
window.renred_explore_page()

if window.prev_state
window.cached_explore.scroll_back location.pathname

Preserve page state for revisiting using browser back button

The browser loads the page as it was first received. Any DOM modifications done via javascript will not be preserved.

If you want to preserve the modifications you will have to do some extra work. After you modify the DOM, update the url hash with an identifier that you can later parse and recreate the modification. Whenever the page is loaded you need to check for the presence of a hash and do the DOM modifications based on the identifier.

For example if you are displaying user information dynamically. Every time you display one you would change the url hash to something like this: "#/user/john". Whenever the page loads you need to check if the hash exists (window.location.hash), parse it, and load the user information.

Update current page URL but maintain the back button state

Well now that I know there is such a thing as window.location.replace maybe this is not the best solution anymore, but its still a solution:

A solution: stop putting the colors in the address itself. Just have the colors dynamically change on the page. Maybe send an Ajax request to save the most recent color on the server session in case the user refreshes the page. Then on page refresh, the PHP page (or ASP or whatever you use) will print the most recent color into your JS variable, and the same color will be shown without the address being changed and without the back button being broken.

Back Button Handle A Dynamic Form

I can't find a prewritten library for this, but I'm sure its been solved before. If I had to it myself I would take this approach:

  1. Use the command pattern so that each method which modifies the page's UI by adding controls also invokes an AJAX method to push the method invoked (textual Javascript representation) onto a queue stored in the server's session.

  2. After body onLoad completes, use an AJAX method to query the server's session for a command queue for the page the user is on. If one is retrieved, just eval each member of the queue to rebuild the page's UI in the same order the user did it.

Keep in mind with this approach you are recording not just additions of controls, but removals as well. You will require separate state holders for user input controls, like text boxes (you will also likely need server-side session with AJAX method access).

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

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.



Related Topics



Leave a reply



Submit