Automatically Saving Form Values In localStorage Cache
Published:
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);