Most software applications need to store data in
some sort of persistent fashion in order to be useful. When it comes to web
apps, this task has traditionally been handled with either a server-side
database or cookies set in the browser. With the advent of HTML5, web
developers now have a couple more options: Web Storage, and Web SQL Database.
1. Web Storage
Web Storage comes in two flavors—localStorage and
sessionStorage—and are very similar to cookies in that
they allow you to use JavaScript to set name/value pairs that you can
retrieve across multiple page reloads.
Unlike cookies, however, Web Storage data is
not sent across the wire with the browser request—it lives entirely in the
client. Therefore, it’s feasible to store much more data than you would
want to with cookies.
Note:
At the time of this writing, browser size
limits for Web Storage are still in flux. However, my most recent tests
indicate that the limit is right around 2.5 MB.
Functionally, localStorage
and sessionStorage are the same. They differ only in
terms of persistence and scope:
localStorage
Data is saved even after the window is closed and is available
to all windows (or tabs) that are loaded from the same source (must
be the same domain name, protocol, and port). This is useful for
things like application preferences.
sessionStorage
Data is stored with the window object. Other windows/tabs are
not aware of the values, and the data is discarded when the
window/tab is closed. Useful for window-specific state like active tab
highlight or the sort order of a table.
Note:
In any of the following examples, you can
substitute sessionStorage anywhere you see
localStorage, but remember that sessionStorage
goes away when you close the window or tab.
Setting a value is as simple as the
following:
localStorage.setItem('age', 40);
Accessing a stored value is equally
simple:
var age = localStorage.getItem('age');
You can delete a specific key/value pair from
storage like so:
localStorage.removeItem('age');
Or, you can delete all key/value pairs like
so:
localStorage.clear();
Assuming your keys are valid JavaScript tokens
(e.g., no spaces, no punctuation other than underscores) you can use this
alternate syntax:
localStorage.age = 40 // Set the value of age
var age = localStorage.age; // Get the value of age
delete localStorage.age; // Remove age from storage
Note:
The localStorage and
sessionStorage keys are stored separately. If you use
the same key name for each, they will not conflict with each
other.
1. Saving User Settings to Local Storage
We are going to be writing a fair amount of
JavaScript in this article, and I don’t want to jam it all in the head
section of our HTML document. To keep our code organized, create a file
called kilo.js in the same directory as your HTML
document, and update the head of your HTML document with a reference to
kilo.js:
<head>
<title>Kilo</title>
<link type="text/css" rel="stylesheet" media="screen"
href="jqtouch/jqtouch.css">
<link type="text/css" rel="stylesheet" media="screen"
href="themes/jqt/theme.css">
<script type="text/javascript" src="jqtouch/jquery.js"></script>
<script type="text/javascript" src="jqtouch/jqtouch.js"></script>
<script type="text/javascript" src="kilo.js"></script>
</head>
Alert readers will notice that I’ve also
removed the jQTouch constructor from the head of the HTML document. It’s
not gone, though; I just moved it into kilo.js. Be
sure you remove that from your main HTML file and create the
kilo.js file in the same directory with the
following contents, then reload the main HTML document in your browser
to make sure it’s still working:
var jQT = $.jQTouch({
icon: 'kilo.png'
});
With that little bit of code reorganization
out of the way, it’s time to add the code needed to save the settings.
You need to override the submit action of the Settings form and replace
it with a custom function called saveSettings(). Thanks
to jQuery, you can accomplish this with a single line of code, which you
must place in the document ready function. Add the following to
kilo.js:
$(document).ready(function(){
$('#settings form').submit(saveSettings);
});
The net result of this is that when the user
submits the settings form, the saveSettings() function will
run instead of the form actually getting submitted.
When the saveSettings() function
is called, it grabs the values from the three form inputs
using jQuery’s val() function and saves each in a
localStorage variable of the same name. Add this function
to kilo.js:
function saveSettings() {
localStorage.age = $('#age').val();
localStorage.budget = $('#budget').val();
localStorage.weight = $('#weight').val();
jQT.goBack();
return false;
}
Once the values are stored, use the jQuery goBack() function (on the
second-to-last line) to dismiss the panel and return to the previous
page. Next, return false to prevent the default action of
the submit event that triggers this function. Had we omitted this line,
the current page would reload, which is not what we want.
At this point, a user can launch the app,
navigate to the Settings panel, enter her settings, and submit the form
to save the settings to localStorage.
Since we are not clearing the fields when the
form is submitted, the values that the user enters will still be there
when she navigates back to the Settings panel. However, this is not
because the values have been saved to localStorage;
it’s because they are still sitting there after having been typed
in.
Therefore, the next time the user launches
that app and navigates to the Settings panel, the fields will be empty,
even though they have been saved.
To remedy this, we need to load the settings
using the loadSettings() function, so add the
following function to kilo.js:
function loadSettings() {
$('#age').val(localStorage.age);
$('#budget').val(localStorage.budget);
$('#weight').val(localStorage.weight);
}
The loadSettings() function is
the opposite of the saveSettings() function; it uses jQuery’s
val() function to set the three fields of the Settings form
to the corresponding values saved in localStorage.
Now that we have a
loadSettings() function, we need to trigger it. The most
obvious time to do this is when the app launches. To make this happen,
simply add a line to the document ready function in
kilo.js:
$(document).ready(function(){
$('#settings form').submit(saveSettings);
loadSettings();
});
Unfortunately, loading the settings only at
startup leaves a loophole that occurs if the user navigates to the
Settings panel, changes some values, and taps the Cancel button without
submitting the form.
In this case, the newly changed values will
still be sitting there the next time the user visits the Settings panel;
not because the values were saved (they weren’t), but because they are
still just sitting there. If the user closes and reopens the app, the
displayed values will revert to the saved values because the
loadSettings() function will refresh them at
startup.
There are several ways to rectify this
situation, but I think the most appropriate is to refresh the displayed
values whenever the Settings panel begins to move, either into or out of
view.
Thanks to jQTouch, this is a simple matter of binding the
loadSettings() function to the
pageAnimationStart event of the Settings panel. Replace the
line you just added with the code shown in bold:
$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
});
The JavaScript contained in the
kilo.js file now provides persistent data support
for the Settings panel. When you view the code we’ve written to make
this happen, there’s really not much to it. Here is everything in
kilo.js so far:
var jQT = $.jQTouch({
icon: 'kilo.png'
});
$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
});
function loadSettings() {
$('#age').val(localStorage.age);
$('#budget').val(localStorage.budget);
$('#weight').val(localStorage.weight);
}
function saveSettings() {
localStorage.age = $('#age').val();
localStorage.budget = $('#budget').val();
localStorage.weight = $('#weight').val();
jQT.goBack();
return false;
}
2. Saving the Selected Date to Session Storage
Ultimately, what we want to do is set up the Date panel so that when it’s displayed, it will check the
database for any records entered for that date and display them as an
edge-to-edge list. This requires that the Date panel know which date the
user tapped on the Dates panel.
We also want to allow the user to add and
delete entries from the database, so we’ll have to add support for the +
button that already exists on the Date panel, and for the Delete button
in the Date panel entry template (more on this later).
The first step is to let the Date panel know
which item the user clicked when she navigated to it from the Dates
panel. With this piece of information, you can calculate the appropriate
date context. To do so, you need to add some lines to the document ready
function in kilo.js:
$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
$('#dates li a').click(function(){
var dayOffset = this.id;
var date = new Date();
date.setDate(date.getDate() - dayOffset);
sessionStorage.currentDate = date.getMonth() + 1 + '/' +
date.getDate() + '/' +
date.getFullYear();
refreshEntries();
});
});
function refreshEntries() {
var currentDate = sessionStorage.currentDate;
$('#date h1').text(currentDate);
}
Next, we’ll move on to a more powerful and
complex client-side data storage method that we’ll use to store the
user’s food entries on the Date panel.