KDawg KDawg - 5 months ago 15
Javascript Question

appendChild() checkboxes: remember selections with browser back button

Thank you in advance to anyone who attempts to help me with this.

I have a form that I am adding checkboxes to via

appendChild()
- as selections for the user to chose from - based on a bunch of criteria.

When the user checks any of these boxes and then clicks the 'continue' button to post the selection to another page - and then clicks the back button - the checkboxes that were checked by the user - have now been forgotten by the browser (no longer checked).

If I use php to write the checkboxes or simply have static checkboxes - when the user checks any of these boxes and then clicks the 'continue' button to post the selection to another page - and then clicks the back button - the selected checkboxes are remembered (still checked)

My question is:

Why does the browser forget the selections the user made when I create the checkboxes with appendChild()

yet the same browser will remember the selections the user made when using static checkboxes

What is it about appendChild() that is not allowing the same browser to remember the checked selection?

[div id="mydiv"] here is where the checkboxes are going[div]


[script type="text/javascript"]

var newInput = document.createElement("INPUT");
newInput.id = "mycheckboxid";
newInput.name = "mycheckboxname";
newInput.type = "checkbox";

document.getElementById('mydiv').appendChild(newInput);

[/script]

Answer

The browser may "forget" dynamic changes to the DOM because different browsers use different strategies for caching web pages. When you hit the back button, the idea is that the browser can display its cached copy rather than re-request the page from the original web server.

It can accomplish this in (at least) two ways:

  1. The browser caches the DOM itself of a page upon leaving it. Upon revisit (forward or back) dynamic changes will persist.
  2. The browser caches only the original HTML of the page at load time (prior to any dynamic changes). This has the effect of losing those dynamic changes--further modification to the DOM with appendChild() or innerHTML is not recorded.

Note that some browsers additionally keep modified form data, and others do not. If your goal is 99+% compatibility across all browsers, then you have some work to do.

To work around this you need to persist the state somehow. You have a few options:

  1. Save data about the modifications to the page to localstorage. Use a key that is generated randomly on first page load and then kept in the page, so that the state changes will only apply to that instance of the page. On page load, if this key already exists, read the change data out and re-apply the changes. Older browsers do not support local storage.

  2. Do the prior thing with cookies. I don't recommend this, as it has the drawback of proliferating cookies. Cookies are sent and received in every request (including ajax ones), so you would be bloating the data being transmitted on every request. Old browsers would work fine with this.

  3. Abandon your dynamic change model and make the changes occur through a post to the server. Then the page will contain the modified html when pulled from the browser's cache. You probably don't want this, but I thought I'd point it out for completeness' sake.

  4. Save data about the modifications to the page via ajax behind the scenes to the server. This is not the same as actually round-tripping each change like the previous item. You still make changes dynamically, but you post an "advisement" file to the server. Then, on each page load, request any adjustment data from the server. This is similar to the first suggestion, but you are using the remote server as your storage. This makes extra net traffic occur on each page load, but the traffic can be minimal as it would be just about this page. It also makes extra net traffic occur that would not normally be sent (the advisement data). A clever system architecture, however, could use this information to persist a user's unsubmitted form data across computers and over time in a way that could be very handy (lets say your user does 199 out of a 200-question survey and then his power goes out--with this scheme he has a chance of painlessly continuing later exactly where he left off!).

  5. Make your Continue button open a new browser window, preserving the original page intact.

  6. Make your Continue button post the data without leaving the page, preserving it intact. You could do a simple lightbox-style overlay.

  7. If the lightbox-style overlay will not work but you really have to display a new page and don't want it to be in a new window, then redesign your site to work similarly to gmail: where pages change only through javascript, and only through using #hash tags at the end of URLs to control behavior. This can be difficult but there are libraries out there that can accomplish it. (For some browsers one has to resort to polling to see if the hashtag has changed.) The basic idea is that when you click a link that points to the same page but has a tag on it such as <a href="#about">About</a> the browser will initiate a page load event, and will push a new context into the history forward/back stack, but will not actually load a new page. You then parse the updated URL for the hash code (which maps to some kind of command) and carry it out. Through careful choice of the proper hash codes for each link, you can hide and display the appropriate page dynamically through Javascript and it will appear as if the person is navigating around a real web site. The reason you do all this is that, because the page never loads, you not only can maintain state in Javascript, you can maintain your DOM state as well--you simply hide the page that was modified by the user, and when the back event occurs that means to visit that page again, you display it, and it is exactly how the user left it. Advantage: If your site requires Javascript to operate, then you are not taking a risk by using even more Javascript to accomplish it. Disadvantage: Completely changing the architecture of your site is a LOT of work and can be difficult to get working on older browsers. To get started with this see Unique URLs. You might try out the jQuery hashchange plugin. If your web site has wide distribution you will want to be sure to address search engine optimization and web usability issues. You may want to see this SO page on detecting back button hash changes.

  8. Use the same strategy as in the prior point but instead of doing it with hashtags, use the new HTML5 history.pushState() and history.replaceState() methods--see Mozilla browser history.

If your goal is not 99% compatibility across 99% of the browsers in use, then please let us know what you are aiming at, as there may be a shortcut possible.

Update: added an option #8

Comments