Time for action – creating a localStorage wrapper
To help get around some of the limitations of localStorage
we are going to create an object called AppStorage
that provides a wrapper over the localStorage
object. The AppStorage
object will help us avoid key collisions and provide an easy way to store non-string values. Let's define this object in a new file called appStorage.js
, so we can reuse it in all of our applications. You can find the code for this section in Chapter 1/example1.3
.
function AppStorage(appName) { var prefix = (appName ? appName + "." : "");
The constructor takes in the application name as a parameter. The next line sets a private variable named prefix
that will be used to prefix all of our keys with the application name to avoid collisions. If an appName
parameter is not provided, it will not use a prefix, which could be useful for data shared among all your applications. If we pass in "myApp"
to the constructor, all of the keys for our app will start with "myApp"
(for example, myApp.settings
or myApp.data
).
This next line creates a public variable that is used to determine if localStorage
is supported by the browser. It simply checks to see if the global localStorage
object exists:
this.localStorageSupported = (('localStorage' in window) && window['localStorage']);
Let's implement the setValue()
method used to set values in local storage first:
this.setValue = function(key, val) { if (this.localStorageSupported) localStorage.setItem(prefix + key, JSON.stringify(val)); return this; };
The setValue()
method takes a key and a value to put into local storage. It prepends the application prefix to the key to help avoid naming collisions. Since you can only put strings into local storage we use the JSON.stringify()
method to convert the value to a string, and then call localStorage.setItem()
to store it.
Now let's implement the getValue()
method to get values from localStorage
:
this.getValue = function(key) { if (this.localStorageSupported) return JSON.parse(localStorage.getItem(prefix + key)); else return null; };
The getValue()
method takes a key, prepends the prefix to it, and returns the string value associated with it in localStorage
. It uses JSON.parse()
to parse the string retrieved from localStorage
into a value. If the key doesn't exist or local storage is not supported, these methods return null
.
The next thing we need is a way to remove items. Let's implement the removeValue()
method to do that. It simply calls localStorage.removeItem()
passing in the prefixed key:
this.removeValue = function(key) { if (this.localStorageSupported) localStorage.removeItem(prefix + key); return this; };
While we're at it, let's add a method to remove all keys for an application. localStorage
does have a clear()
method, but that completely empties out localStorage
for your domain, not just the values for our application. So we need to get all of the keys for our application and then delete them one-by-one:
this.removeAll = function() { var keys = this.getKeys(); for (var i in keys) { this.remove(keys[i]); } return this; };
The removeAll()
method references a getKeys()
method. This method will return an array of all key names for the application. We will make the getKeys()
method, so the user can also pass in a filter function to further filter the results by their own criteria if they wish:
this.getKeys = function(filter) { var keys = []; if (this.localStorageSupported) { for (var key in localStorage) { if (isAppKey(key)) { // Remove the prefix from the key if (prefix) key = key.slice(prefix.length); // Check the filter if (!filter || filter(key)) { keys.push(key); } } } } return keys; }; function isAppKey(key) { if (prefix) { return key.indexOf(prefix) === 0; } return true; };
This method works by looping over all of the keys in localStorage
, which you can get in the same way that you get all of the keys in an object or array, by implementing a loop using the in
keyword. It calls the private method isAppKey()
to determine if the key belongs to our application. If so, it removes the application prefix from the key. Lastly, if no filter is defined or the filter function returns true
, add the key to the array of keys to pass back.
The private isAppKey()
method takes a key name as the parameter and returns true
if the key belongs to our application. If an application name prefix is not defined there's nothing to check. Otherwise we check to see if the key starts with the application prefix.
There's one last public method we need to write. The contains()
method will determine if there is a value associated with a key. It simply tries to get the value associated with the key and checks to see if it exists:
this.contains = function(key) { return this.get(key) !== null; };
What just happened?
We created a wrapper object called AppStorage
over the HTML5 localStorage
object. It encapsulates all of the behavior for interacting with localStorage
and saving JavaScript objects to it. Now we can save any type of data to localStorage
and then retrieve it.