Web storage allows us to store simple key/value data in the browser. Wen storage is similar to cookies, but better implemented and we can store greater amounts of data. There are two kinds of web storage – local storage and session storage. Both types share the same mechanism, but the visibility of the stored data and its longevity differ. Table 39-1 provides the summary for this chapter.
Tip There is another storage specification, the Indexed Database API, which allows richer data storage and SQL-like queries. This specification is still volatile and the browser implementations are experimental and unstable as I write this.
We access the local storage feature through the localStorage
global property – this property returns a Storage
object, which is described in Table 39-2. The Storage
object is used to store pairs of strings, organized in key/value form.
The Storage
object allows us to store key/value pairs where both the key and the value are strings. Keys must be unique, which means the value is updated if we call the setItem
method using a key that already exists in the Storage
object. Listing 39-1 shows how we can add, modify, and clear the data in the local storage.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style>
body > * {float: left;}
table {border-collapse: collapse; margin-left: 50px}
th, td {padding: 4px;}
th {text-align: right;}
input {border: thin solid black; padding: 2px;}
label {min-width: 50px; display: inline-block; text-align: right;}
#countmsg, #buttons {margin-left: 50px; margin-top: 5px; margin-bottom: 5px;}
</style>
</head>
<body>
<div>
<div><label>Key:</label><input id="key" placeholder="Enter Key"/></div>
<div><label>Value:</label><input id="value" placeholder="Enter Value"/></div>
<div id="buttons">
<button id="add">Add</button>
<button id="clear">Clear</button>
</div>
<p id="countmsg">There are <span id="count"></span> items</p>
</div>
<table id="data" border="1">
<tr><th>Item Count:</th><td id="count">-</td></tr>
</table>
<script>
displayData();
var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = handleButtonPress;
}
function handleButtonPress(e) {
switch (e.target.id) {
case 'add':
var key = document.getElementById("key").value;
var value = document.getElementById("value").value;
localStorage.setItem(key, value);
break;
case 'clear':
localStorage.clear();
break;
}
displayData();
}
function displayData() {
var tableElem = document.getElementById("data");
tableElem.innerHTML = "";
var itemCount = localStorage.length;
document.getElementById("count").innerHTML = itemCount;
for (var i = 0; i < itemCount; i++) {
var key = localStorage.key(i);
var val = localStorage[key];
tableElem.innerHTML += "<tr><th>" + key + ":</th><td>"
+ val + "</td></tr>";
}
}
</script>
</body>
</html>
In this example, I report on the number of items in the local storage and enumerate the set of stored name/value pairs to populate a table element. I have added two input
elements, and I use their contents to store items when the Add
button is pressed. In response to the Clear
button, I clear the contents of the local storage. You can see the effect in Figure 39-1.
The browser won't delete the data we add using the localStorage
object unless the user clears the browsing data. (The specification also allows the data to be removed for security reasons, but the kind of security problems that require local data to be deleted are not articulated.)
The data stored via the local storage feature is available to any document that has the same origin. The storage
event is triggered when one document makes a change to the local storage and we can listen to this event in other documents from the same origin to make sure that we stay abreast of changes.
The object dispatched with the storage event is a StorageEvent
object, whose members are described in Table 39-3.
Listing 39-2 shows a document, which I have saved as storage.html
, that listens and catalogues the events issued by the local storage object.
<!DOCTYPE HTML>
<html>
<head>
<title>Storage</title>
<style>
table {border-collapse: collapse;}
th, td {padding: 4px;}
</style>
</head>
<body>
<table id="data" border="1">
<tr>
<th>key</th>
<th>oldValue</th>
<th>newValue</th>
<th>url</th>
<th>storageArea</th>
</tr>
</table>
<script>
var tableElem = document.getElementById("data");
window.onstorage = handleStorage;
function handleStorage(e) {
var row = "<tr>";
row += "<td>" + e.key + "</td>";
row += "<td>" + e.oldValue + "</td>";
row += "<td>" + e.newValue + "</td>";
row += "<td>" + e.url + "</td>";
row += "<td>" + (e.storageArea == localStorage) + "</td></tr>";
tableElem.innerHTML += row;
};
</script>
</body>
</html>
The storage
event is triggered through the Window
object of any document that shares the changed storage. In this example, I add a new row to a table
element each time an event is received – you can see the effect in Figure 39-2.
The events in the figure show me adding new items to local storage. The sequence was:
Banana
/Yellow
Apple
/Red
Apple
to Green
Cherry
/Red
Clear
button (which calls the clear
method)You can see that null
is used when there is no value to report in the event. For example, when I add a new item to storage, the oldValue
property returns null
. The last event in the table has the key
, oldValue,
and newValue
properties as null
. This is the event that was triggered in response to the clear
method being called, which removes all of the items from storage.
The url
property helpfully tells us which document has triggered the change. The storageArea
property returns the Storage
object that has changed, which can be the local or session storage objects (I'll explain session storage shortly). For this example, we only receive events from the local storage object.
Note Events are not dispatched within the document that made the change. I guess it is assumed that we already know what happened. The events are only available in other documents from the same origin.
Session storage works just like local storage, except that the data is private to each browsing context and is removed when the document is closed. We access session storage through the sessionStorage
global variable, which returns a Storage
object (previously described in Table 39-2). You can see session storage in use in Listing 39-3.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style>
body > * {float: left;}
table {border-collapse: collapse; margin-left: 50px}
th, td {padding: 4px;}
th {text-align: right;}
input {border: thin solid black; padding: 2px;}
label {min-width: 50px; display: inline-block; text-align: right;}
#countmsg, #buttons {margin-left: 50px; margin-top: 5px; margin-bottom: 5px;}
</style>
</head>
<body>
<div>
<div><label>Key:</label><input id="key" placeholder="Enter Key"/></div>
<div><label>Value:</label><input id="value" placeholder="Enter Value"/></div>
<div id="buttons">
<button id="add">Add</button>
<button id="clear">Clear</button>
</div>
<p id="countmsg">There are <span id="count"></span> items</p>
</div>
<table id="data" border="1">
<tr><th>Item Count:</th><td id="count">-</td></tr>
</table>
<script>
displayData();
var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = handleButtonPress;
}
function handleButtonPress(e) {
switch (e.target.id) {
case 'add':
var key = document.getElementById("key").value;
var value = document.getElementById("value").value;
sessionStorage.setItem(key, value);
break;
case 'clear':
sessionStorage.clear();
break;
}
displayData();
}
function displayData() {
var tableElem = document.getElementById("data");
tableElem.innerHTML = "";
var itemCount = sessionStorage.length;
document.getElementById("count").innerHTML = itemCount;
for (var i = 0; i < itemCount; i++) {
var key = sessionStorage.key(i);
var val = sessionStorage[key];
tableElem.innerHTML += "<tr><th>" + key + ":</th><td>"
+ val + "</td></tr>";
}
}
</script>
</body>
</html>
This example works in the same way as the one for local storage, except the visibility and life are restricted. These restrictions have a consequence on how the storage
event is dealt with – remember that storage events are only triggered for documents that share storage. In the case of session storage, this means that the events will be triggered only for embedded documents, such as those in an iframe
. Listing 39-4 shows an iframe
added to the previous example which contains the storage.html document.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style>
body > * {float: left;}
table {border-collapse: collapse; margin-left: 50px}
th, td {padding: 4px;}
th {text-align: right;}
input {border: thin solid black; padding: 2px;}
label {min-width: 50px; display: inline-block; text-align: right;}
#countmsg, #buttons {margin-left: 50px; margin-top: 5px; margin-bottom: 5px;}
iframe {clear: left;}
</style>
</head>
<body>
<div>
<div><label>Key:</label><input id="key" placeholder="Enter Key"/></div>
<div><label>Value:</label><input id="value" placeholder="Enter Value"/></div>
<div id="buttons">
<button id="add">Add</button>
<button id="clear">Clear</button>
</div>
<p id="countmsg">There are <span id="count"></span> items</p>
</div>
<table id="data" border="1">
<tr><th>Item Count:</th><td id="count">-</td></tr>
</table>
<iframe src="storage.html" width="500" height="175"></iframe>
<script>
displayData();
var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = handleButtonPress;
}
function handleButtonPress(e) {
switch (e.target.id) {
case 'add':
var key = document.getElementById("key").value;
var value = document.getElementById("value").value;
sessionStorage.setItem(key, value);
break;
case 'clear':
sessionStorage.clear();
break;
}
displayData();
}
function displayData() {
var tableElem = document.getElementById("data");
tableElem.innerHTML = "";
var itemCount = sessionStorage.length;
document.getElementById("count").innerHTML = itemCount;
for (var i = 0; i < itemCount; i++) {
var key = sessionStorage.key(i);
var val = sessionStorage[key];
tableElem.innerHTML += "<tr><th>" + key + ":</th><td>"
+ val + "</td></tr>";
}
}
</script>
</body>
</html>
You can see how the events are reported in Figure 39-3.
In this chapter, I have described the web storage feature, which allows us to store key/value pairs in the browser. This is a simple feature, but the longevity of local storage can make it especially useful, particularly for storing simple user preferences.
3.149.249.127