2. Storing Database Tables with JavaScript's localStorage API

In most apps, we have some form of data management where data is represented in tables such that table rows correspond to objects, and the table schema corresponds to the objects' type. When building a front-end web app with JavaScript, the simplest approach for persistent data storage is using JavaScript's localStorage API, which provides a simple key-value database, but does not support database tables. So, the question is: how can we store and retrieve tables with Local Storage?

We show how to represent database tables in JavaScript in the form of (what we call) JSON tables, and how to store these tables in Local Storage.

2.1. Entity Tables

The JavaScript Object Notation (JSON) defines a concise syntax for JavaScript array literals (lists) and JavaScript object literals (maps):

  • Lists are expressed as comma-separated lists of data literals enclosed in brackets:

    ["penguin", "arctis", "snow"]
  • Maps are expressed as comma-separated lists of key-value slots enclosed in curly braces:

    {"id": 2901465, "my phone number":"0049.30.227109"}

    A record is a special type of map where the keys are admissible JavaScript identifiers denoting properties, so they need not be enclosed in quotation marks in JavaScript code. For example, {id: 2901465, phone:"0049.30.227109"} is a record. The value of a property in a record, or the value associated with a key in a map, may be a simple data literal, or an array literal, or another object literal as in:

    {tags:["penguin","arctis"], photographer:{"last":"Wagner","first":"Gerd"}}

A entity table contains a set of records (or table rows) such that each record represents an object with a standard identifier property slot. Consequently, an entity table can be represented as a map of records such that the keys of the map are the values of the standard identifier property, and their associated values are the corresponding records, as illustrated by the following example:

Table 2.3. A entity table representing a collection of books

Key Value
006251587X { isbn:"006251587X," title:"Weaving the Web", year:2000 }
0465026567 { isbn:"0465026567," title:"Gödel, Escher, Bach", year:1999 }
0465030793 { isbn:"0465030793," title:"I Am A Strange Loop", year:2008 }

2.2. JavaScript's LocalStorage API

For a front-end app, we need to be able to store data persistently on the front-end device. Modern web browsers provide two technologies for this purpose: the simpler one is called Local Storage, and the more powerful one is called IndexDB. For simplicity, we use the Local Storage API in our example app.

A Local Storage database is created per browser and per origin, which is defined by the combination of protocol and domain name. For instance, http://example.com and http://www.example.com are different origins because they have different domain names, while http://www.example.com and https://www.example.com are different origins because of their different protocols (HTTP versus HTTPS).

The Local Storage database managed by the browser and associated with an app (via its origin) is exposed as the built-in JavaScript object localStorage with the methods getItem, setItem, removeItem and clear. However, instead of invoking getItem and setItem, it is more convenient to handle localStorage as a map, writing to it by assigning a value to a key as in localStorage["id"] = 2901465, and retrieving data by reading the map as in var id = localStorage["id"]. The following example shows how to create an entity table and save its serialization to Local Storage:

var persons = {};
persons["2901465"] = {id: 2901465, name:"Tom"};
persons["3305579"] = {id: 3305579, name:"Su"};
persons["6492003"] = {id: 6492003, name:"Pete"};
try {
  localStorage["personTable"] = JSON.stringify( persons);
} catch (e) {
  alert("Error when writing to Local Storage\n" + e);
}

Notice that we have used the predefined method JSON.stringify for serializing the entity table persons into a string that is assigned as the value of the localStorage key "personTable". We can retrieve the table with the help of the predefined de-serialization method JSON.parse in the following way:

var persons = {};
try {
  persons = JSON.parse( localStorage["personTable"]);
} catch (e) {
  alert("Error when reading from Local Storage\n" + e);        
}