Fragmented Thought

Automatically Saving Form Values In localStorage Cache

By

Published:

Lance Gliser

Heads up! This content is more than six months old. Take some time to verify everything still works as expected.

As part of the rewrite of a major application process for a client, they have requested the ability to navigate away from the form and come back to finish later. We suggested using database storage at the server, but it was declined as they did not want to use logins, and IP based retrieval could be less secure than desired. They did however, jump at the ability to save data permanently in the user's browser allowing them to come back at need, potentially even year over year. Thus began a small foray into auto persisting forms using localStorage. There's way more to the application than is represented here, but I've pulled the auto-saving piece out as I find it extremely useful in a generic sense.

I've created a small framework, mostly to designate a place for data to be kept for easy saving. As a handy side note, this also makes sending the same saved data to the server for login based persistence, or form processing a breeze. Using this code, any input, select, textarea, or button with a name when changed will automatically write the full contents of form data into localStorage. Loading the page again will automatically put all values back as they belong, and fire change events along the way ensuring most form bound behaviors are triggered. The data object is rather extensible. Using a different namespace such as application.storage.data.addresses, you can keep other sorts of data, I'm using that for a separate address book among other things.

application = { ready: function () { application.storage.ready(); application.form.ready(); }, }; application.storage = { data: null, ready: function () { try { // Pull our data object out of cache cache = localStorage.getItem("school.enrollment.data"); if (cache == null) { // Create it if it does not yet exist application.storage.data = {}; application.storage.persist(); } else { // Recreate the object from the stored JSON application.storage.data = JSON.parse(cache); } } catch (err) { console.debug("Local Storage error", err); } }, persist: function () { try { // Store the entire data object into local storage as is localStorage.setItem( "school.enrollment.data", JSON.stringify(application.storage.data) ); } catch (err) { console.debug("Local Storage error", err); } }, }; application.form = { fields: {}, ready: function () { // Bind form behaviors // Ensure this form's storage namespace exists if ("form" in application.storage.data == false) { application.storage.data.form = {}; } // Load stored values we placed into form for (var name in application.storage.data.form) { var value = application.storage.data.form[name]; var $element = jQuery('[name="' + name + '"]'); var elementTag = $element[0].nodeName.toLowerCase(); switch (elementTag) { case "button": continue; default: switch ($element.attr("type")) { case "submit": continue; case "radio": case "checkbox": // Check the radio or checkbox associated with this stored value // TODO see what happens if I've stored multiple checkbox values for one name.. // Fire a change event in case the form behaviors above change based on this field jQuery('[name="' + name + '"][value="' + value + '"]') .attr("checked", "checked") .change(); continue; default: // Insert our value // Fire a change event in case the form behaviors above change based on this field $element.val(value).change(); continue; } } } // Bind auto-save behavior jQuery("input[name], select[name], textarea[name], button[name]").change( application.form.fieldChanged ); }, fieldChanged: function (event) { var $this = jQuery(this); var elementTag = this.nodeName.toLowerCase(); switch (elementTag) { case "button": return; default: switch ($this.attr("type")) { case "submit": return; default: var value = $this.val(); } } var name = $this.attr("name"); // Store all form data points into our storage namespace application.storage.data.form[name] = value; // Write to localStorage cache application.storage.persist(); }, }; jQuery(document).ready(application.ready);