Storing Data Client-Side in JavaScript

Simple HTML pages with a bit of JavaScript can be a great format for “mini applications”—small helper programs that automate basic tasks. By connect­ing a few form fields with event handlers, you can do anything from convert­ing between centimeters and inches to computing passwords from a master password and a website name.

When such an application needs to remember something between ses­sions, you cannot use JavaScript bindings—those are thrown away every time the page is closed. You could set up a server, connect it to the internet, and have your application store something there. We will see how to do that in Chapter 20. But that’s a lot of extra work and complexity. Sometimes it is enough to just keep the data in the browser.

The localStorage object can be used to store data in a way that survives page reloads. This object allows you to file string values under names.

localStorage.setItem(“username”, “marijn”);

console.log(localStorage.getItem(“username”));

// → marijn

localStorage.removeItem(“username”);

A value in localStorage sticks around until it is overwritten, it is removed with removeItem, or the user clears their local data.

Sites from different domains get different storage compartments. That means data stored in localStorage by a given website can, in principle, be read (and overwritten) only by scripts on that same site.

Browsers do enforce a limit on the size of the data a site can store in localStorage. That restriction, along with the fact that filling up people’s hard drives with junk is not really profitable, prevents the feature from eat­ing up too much space.

The following code implements a crude note-taking application. It keeps a set of named notes and allows the user to edit notes and create new ones.

Notes: <select></select> <button>Add</button><br>

<textarea style=”width: 100%”></textarea>

<script>

let list = document.querySelector(“select”);

let note = document.querySelector(“textarea”);

let state;

function setState(newState) {

list.textContent = “”;

for (let name of Object.keys(newState.notes)) {

let option = document.createElement(“option”);

option.textContent = name;

if (newState.selected == name) option.selected = true;

list.appendChild(option);

}

note.value = newState.notes[newState.selected];

localStorage.setItem(“Notes”, JSON.stringify(newState));

state = newState;

}

setState(JSON.parse(localStorage.getItem(“Notes”)) || {

notes: {“shopping list”: “Carrots\nRaisins”}, selected: “shopping list”

});

list.addEventListener(“change”, () => {

setState({notes: state.notes, selected: list.value}); });

note.addEventListener(“change”, () => { setState({

notes: Object.assign({}, state.notes,

{[state.selected]: note.value}), selected: state.selected });

});

document.querySelector(“button”)

.addEventListener(“click”, () => {

let name = prompt(“Note name”); if (name) setState({

notes: Object.assign({}, state.notes, {[name]: “”}), selected: name });

});

</script>

The script gets its starting state from the “Notes” value stored in localStorage or, if that is missing, creates an example state that has only a shopping list in it. Reading a field that does not exist from localStorage will yield null. Passing null to JSON.parse will make it parse the string “null” and return null. Thus, the || operator can be used to provide a default value in a situation like this.

The setState method makes sure the DOM is showing a given state and stores the new state to localStorage. Event handlers call this function to move to a new state.

The use of Object.assign in the example is intended to create a new object that is a clone of the old state.notes, but with one property added or overwritten. Object.assign takes its first argument and adds all properties from any further arguments to it. Thus, giving it an empty object will cause it to fill a fresh object. The square brackets notation in the third argument is used to create a property whose name is based on some dynamic value.

There is another object, similar to localStorage, called sessionStorage.

The difference between the two is that the content of sessionStorage is for­gotten at the end of each session, which for most browsers means whenever the browser is closed.

Source: Haverbeke Marijn (2018), Eloquent JavaScript: A Modern Introduction to Programming, No Starch Press; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *