DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Trending

  • Cosmos DB Disaster Recovery: Multi-Region Write Pitfalls and How to Evade Them
  • Agile and Quality Engineering: A Holistic Perspective
  • Why High-Performance AI/ML Is Essential in Modern Cybersecurity
  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways

Saving Form Data in Client-side Storage

A look at using vanilla JavaScript to automatically store and cache form data as a user enters information.

By 
Raymond Camden user avatar
Raymond Camden
·
Apr. 13, 22 · Analysis
Likes (3)
Comment
Save
Tweet
Share
2.6K Views

Join the DZone community and get the full member experience.

Join For Free

Today's post is one of those that started off with me worrying that it was going to be too simple and quickly turned into a bit of a complex little beast. I love that as it usually means my expectations were wrong and I've got a chance to expand my knowledge a bit. This post came from a simple idea: While working on a form, can we save your form data for restoring later in case you navigate away, close the tab by accident, or perhaps get "surprised" by an operating system update. While this is not something you would want to use in every situation (for example, storing a new password field), there are plenty of examples where this could be helpful, especially in a larger form.

For our demo, I will only cover client-side storage, which means the data will be unique to one browser on the device. Although what I described here could be tied to a back-end service for storing temporary form data as well.

Initially, I tried to build a generic solution that would apply to any and all forms but quickly discovered that it became Non-Trivial to the point where I decided a more hard-coded solution would be better. My assumption here is that my readers can take these techniques and apply them to their site with a bit of work. As always, if you have any questions, just let me know!

The Form

Alright, let's start off by looking at the form I'll use for the demo. While covering every unique kind of form field would be overwhelming, I tried to cover the main ones: A few text fields, a set of checkboxes, a set of radio fields, and a text area. Here's the HTML:

HTML
 
<form id="mainForm">
	<p>
	<label for="name">Name</label>
	<input type="text" name="name" id="name">
	</p>
	<p>
	<label for="email">Email</label>
	<input type="email" name="email" id="email">
	</p>
	<p>
	<label for="inus">In US?</label>
	<select name="inus" id="inus">
		<option></option>
		<option value="true">Yes</option>
		<option value="false">No</option>
	</select>
	</p>
	<p>
		<label for="department">Department</label><br/>
		<input type="radio" name="department" id="dept1" value="dept1"><label for="dept1">Dept 1</label><br/>
		<input type="radio" name="department" id="dept2" value="dept2"><label for="dept2">Dept 2</label><br/>
		<input type="radio" name="department" id="dept3" value="dept3"><label for="dept3">Dept 3</label><br/>
</p>
<p>
	<label for="cookie">Favorite Cookie (Select as many as you want):</label><br/>
	<input type="checkbox" name="cookie" id="cookie1" value="Chocolate Chip"><label for="cookie1">Chocolate Chip</label><br/>
	<input type="checkbox" name="cookie" id="cookie2" value="Sugar"><label for="cookie2">Sugar</label><br/>
	<input type="checkbox" name="cookie" id="cookie3" value="Ginger"><label for="cookie3">Ginger</label><br/>
	<input type="checkbox" name="cookie" id="cookie4" value="BW"><label for="cookie4">Black & White</label><br/>
</p>		
<p>
	<label for="comments">Comments</label><br/>
	<textarea name="comments" id="comments"></textarea>
</p>
<p>
	<input type="submit">
</p>
</form>

It's not terribly exciting but gets the job done in terms of demonstrating multiple types of form fields. 

html form

Saving Form Data

Let's begin with how to save the form. Here's the high-level approach I'm going to use:

  • The data will be stored in LocalStorage. This will let it persist forever (not really, but close enough) and will be an incredibly simple API to work with. IndexedDB can store a lot more data, but all we're storing is a form.
  • I will persist the data on every change. We could get fancy and save on an interval, but it's relatively inexpensive to just save on every change.

To begin, I set up my code to fire some logic on DOMContentLoaded as well as create some global variables:

JavaScript
 
document.addEventListener('DOMContentLoaded',init,false);

let name, email, inus, depts, cookies, comments;

Now let's look at init: 

JavaScript
 
function init() {
	// get the dom objects one time
	name = document.querySelector('#name');
	email = document.querySelector('#email');
	inus = document.querySelector('#inus');
	depts = document.querySelectorAll('input[name=department]');
	cookies = document.querySelectorAll('input[name=cookie]');
	comments = document.querySelector('#comments');
	
	// listen for input on all
	let elems = Array.from(document.querySelectorAll('#mainForm input, #mainForm select, #mainForm textarea'));
	elems.forEach(e => e.addEventListener('input', handleChange, false));
}

As I mentioned above, I'm not going for a generic solution, but rather one tied to my exact form. You can see then I create a variable representing the DOM item for each of my fields. depts and cookies ae special as they are a set of items, not just one.

But while I'm not going dynamic to set up the variables pointing to the form fields, I did go dynamic to set up the event handler. I could have added an event listener for each of my variables (while ensuring I handled depts and cookies in a loop), but this shortcut handles matching any form fields inside my form and then letting me quickly assign the handler for each.

Now that we've got event handlers, we can build logic to persist the form. This handler will fire on any change in the fields, but as I said above, we'll get all the data and persist.

JavaScript
 
function handleChange(e) {
	
	console.log('handleChange');
	/*
	get all values and store
	first the easy ones
	*/
	let form = {};
	form.name = name.value;
	form.email = email.value;
	form.inus = inus.value;
	form.comments = comments.value;
	// either null or one
	depts.forEach(d => {
		if(d.checked) form.department = d.value;
	});
	// either empty array or some things
	form.cookies = [];
	cookies.forEach(c => {
		if(c.checked) form.cookies.push(c.value);
	});
	
	// now store
	saveForm(form);
}

I create an object, formto store my data, and then get the "simple" ones where I can just check the value. This works for the select tag too. For the radio and checkbox ones, I handle them a bit differently. The radio one, deptswill either have nothing selected or one, so if nothing is picked, it's never saved, or it's a value. For cookies, I'll always have an empty array at a minimum, but will fill it with the values when selected.

Finally, I take the data and pass it to another function. The code to use LocalStorage is very simple, but I wanted it abstracted in case the decision was made to change to something else in the future. Here's that function:

JavaScript
 
function saveForm(form) {
	let f = JSON.stringify(form);
	window.localStorage.setItem('form', f);
}

Remember that LocalStorage only takes simple values, so the object is serialized to a string first.

Woot! Ok, at this point, I can type in data, and confirm it's working in DevTools:
Devtools output

Retrieving the Data

Now that there's a way to store the form, let's look at fetching the data (if it exists) and using it. Back in init, I added the following:

JavaScript
 
// do we have a cached form?
let cached = getForm();
if(cached) {
	name.value = cached.name;
	email.value = cached.email;
	inus.value = cached.inus;
	comments.value = cached.comments;
	if(cached.department) {
		depts.forEach(d => {
			if(d.value === cached.department) d.checked = true;
		});
	}
	if(cached.cookies) {
		cookies.forEach(c => {
			if(cached.cookies.includes(c.value)) c.checked = true;
		});
	}
}

I begin by fetching the form (I'll show that in a second) and if the cache exists, I make use of it. All the simple values and the select, it's easy to set. For the checkbox and radio ones, it's slightly more complex. depts will either be null or a value, but cookies will be an array (technically it will always exist so if isn't really necessary) and I make use includes to check the cached array.

As with saveForm, I wanted to wrap the cache retrieval logic to handle updating the storage in the future. Here's getForm:

JavaScript
 
function getForm() {
	let f = window.localStorage.getItem('form');
	if(f) return JSON.parse(f);
}

There's one last thing to do. When the form is submitted, it makes sense to clear the cache. I added this to the end of init: 

JavaScript
 
document.querySelector('#mainForm').addEventListener('submit', () => {
	window.localStorage.removeItem('form');
}, false);

This is nice and simple, but I'm being a bit inconsistent here by not abstracting out how I work with persistence. It's one line, and I feel kinda bad about it, but I'm also fine leaving it for now.

Here's the complete demo for you to play with: Demo

Published at DZone with permission of Raymond Camden, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!