Fun with HTML5 localStorage API

Recently had occasion to wonder if I should be storing data in localStorage when available. Thanks to two notable resources (among many others I checked out tonight) I had a little bit of fun and learned a few things; enough to get comfortably started with localStorage. Here are my two takeaways:

Sanity Check It

If you’re going to implement a localStorage solution, you need to make sure that the API is available in the user’s browser, and warn if there’s no room for the data in the localStorage database (there’s a size limit of ‘only’ 5MB). I won’t rewrite code and pretend it’s someone else’s, so credit where it’s due. This snippet from Paperkilled’s Tutorial encapsulates both of these:

if (typeof(localStorage) == 'undefined' ) {
  alert('Your browser does not support HTML5 localStorage. Try upgrading.');
} else {
  try {
    localStorage.setItem("name", "Hello World!"); //saves to the database, "key", "value"
  } catch (e) {
    if (e == QUOTA_EXCEEDED_ERR) {
    alert('Quota exceeded!'); //data wasn't successfully saved due to quota exceed so throw an error
    }
  }
}

Of course, the expectation is that for production code you would provide more in-depth handling, but the basics are pretty clear. Check for the presence of the localStorage function, then try writing to it in a try/catch block. The try/catch will obviously handle more than just the Quota issue, so you probably want to ‘alert’ (the author swaps out alerts later) other errors, too.

Storing Objects

In some sort of fit of madness, the current implementations only allow key:value pairs, and those must be strings. An application that relies on localStorage will certainly need to cast everything to string, as the browser will not do it automatically as of this writing. But there’s something even more fundamentally wrong with the straight-up key:value storage, in my opinion:

You cannot directly write objects!

JSON is a hugely popular data interchange format, and (without statistical evidence to back me) I would venture that it’s the most common one for JavaScript-driven applications. It makes some sort of broken sense: objects can contain data other than strings, so why would you be able to write them if you can’t write strings? But it blew me away as being a huge oversight. But I digress. I found a thread at Stack Overflow called Storing Objects in HTML5 localStorage that provided a number of solutions.

Some people seem to love extending native API’s with prototyping. I liked a less-voted-up solution that simply provided a new object to act as a “facade” for localStorage. What this means is that rather than extending or overwriting the native function, it is abstracted away to another new function that will use the native method once the criteria (string, remember!) is met. Forgetting about sanity checks, here’s the basics you need to get started:

// data setter and getter
var data = {
    localStorage: {
        set: function(key, value) {
            if (typeof value == "object") {
                value = JSON.stringify(value);
            }
            localStorage.setItem(key, value);
        },
        get: function(key) {
            var value = localStorage.getItem(key);
            // assume it is an object that has been stringified
            if (value[0] == "{") {
                value = JSON.parse(value);
            }

            return value;
        }
    }
};

// testing
data.localStorage.set('test', {
    'me': 'Greg',
    'wife' : 'Schmoopie',
    'son': 'Monkey'
});

var retrieved = data.localStorage.get('test');
var dump;
for (key in retrieved) {
    document.write('Key is "' + key + '" and value is "' + retrieved[key] + '"<br/>');
    // Key is "me" and value is "Greg"
    // Key is ... etc ...
}​​​​​​​​​​​​​​​​​​​

Awesome! Stringify on the way in, decode on the way out. Now you can store multi-dimensional objects with no fear.

Leave a Reply