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) entity tables, and how to store these tables in Local Storage.
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"}}
An 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:
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 } |
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 IndexedDB.
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); }