Real-World Off-Line Data Storage

In many projects there comes a time when you'll need to store some data off-line. It may be a requirement or just an improvement for your users, but you have to decide which of the available storage options you will use in your application. This article will help you choose the best one, for your app.


Introduction

HTML5 introduced a few off-line storage options. AppCache, localStorage, sessionStorage and IndexedDB. Every one of them is suitable for a specific use. For example, AppCache can boost your application or let some parts of it work without an Internet connection. Below, I will describe all of these options and show a few code snippets with example usage.


AppCache

If a part of your application (or the whole app) can be used without access to the server, you can use AppCache to enable your users to do some things off-line. All you need to do is to create a manifest file where you would specify what should be cached and what shouldn't be. You can also specify replacements for the files that require on-line access.

An AppCache manifest is just a text file with a .appcache (recommended) extension. It starts with CACHE MANIFEST and is divided in to three parts:

  • CACHE - files you specify here will be downloaded and cached the first time the user accesses your site
  • NETWORK - here you list the files that require an Internet connection to work properly, they will never be cached
  • FALLBACK - these files will be used when an on-line resource is accessed without a connection

Example

First, you have to define the manifest file on your page:

You need to remember that the manifest file must be served with a text/cache-manifest MIME-type, otherwise it will not be parsed by the browser. Next, you need to create the file you defined earlier. For the purpose of this example, let's imagine that you have an informational website with the ability to contact you and write comments. You can let users access the static parts of the site and replace the contact form and comments with other information so that the form and comments are inaccessible while off-line.

First, let's define some static content:

Side Note: one bad thing about the manifest is that you can't use a wildcard sign to indicate that, for example, a whole folder should be cached, you can only use a wildcard under the NETWORK section to indicate that all resources not listed in the manifest should not be cached.

You don't need to cache the page on which the manifest is defined, it will be cached automatically. Now we will define fallbacks for the contact and comments sections:

Finally, we can use an * to stop all other resources from being cached:

The final result should look like this:

An important thing to remember is that your resources will only be cached once. They will not get cached when you update them, only when you change the manifest. A good practice is to enter in a comment with a version number and increase it every time you update the file:


LocalStorage & SessionStorage

These two storage options will be useful if you want to preserve something in your JavaScript code. The first one lets you save a value without an expiration date. This value will be accessible for any page with the same domain and protocol. For example, you may want to save the user's application settings on his/her computer so he/she can adjust them to the computer they currently use. The second one will hold the values until the user closes the browser window (or tab). Also, the data is not shared between windows, even if the user opens a few pages of your application.

Something worth remembering is that you can store only basic types in localStorage/sessionStorage. So only strings and numbers will work. Everything else will be stored using it's toString() method. If you need to save an object, you should do it using JSON.stringify (if this object is a class, you can just override the default toString() method to do it for you automatically).

Example

Let's consider the previous example. In the comments and contact sections of the site, we can save what the user typed in, so if he/she accidentally closes the window, the values will still be there for him/her to continue later on. This will be a really simple piece of code using jQuery (since we will be using a field's id to identify it later, each of the form fields will need to have an id attribute)

When the comment/contact form is sent, we have to clear the value. Let's do this by handling a submit event (here's the most basic example):

And finally, on page load, we will restore the values:


IndexedDB

This is the most interesting storage option in my opinion. It allows you to store rather large amounts of indexed data into the user's browser. This way, you can save complex objects, large documents, etc. and have your user access them without an Internet connection. This feature is useful for all kinds of applications - if you are making an email client, you can save the user's emails so he/she can access them later, a photo album could save photos for off-line use, or GPS navigation can save a particular route and the list goes on.

IndexedDB is an object-oriented database. This means that there are no tables and no SQL. You store key-value pairs of data, where keys are strings, numbers, dates or arrays and values can be complex objects. The database itself is composed from stores. A store is similar to a table in a relational database. Each value must have it's own key. A key can be generated automatically, you can specify it when you add the value, or it can be some field in the value (which can also be generated automatically). If you decide to use a field as a key, you will only be able to add JavaScript objects to the store (because simple numbers or strings can't have any properties like objects can).

Example

For this example, let's imagine that we have a music album. Now, I'm not going to cover building the entire music album app here. I will only be covering the IndexedDB part of the app, but the music album app itself is included with this article for you to download, so you can look at the complete source code there. First, we have to open the database and create the store:

The above code is pretty simple. You probably noticed the version and the onupgradeneeded event. This event is fired when the database is opened with a new version. Since the database didn't exist yet, the event fires and we can create the store we need. Later we add two indexes, one to search by title and one to search by band. Now let's see the process of adding and removing albums:

Pretty straightforward. You need to remember that all operations on the database are based on transactions to preserve consistency of data. Now the only thing left to do is to display the albums:

This is also not very complicated. As you can see, using IndexedDB you can store complex values really easily. You can also search for values by index, like this:

You can use the cursor with the index just like how we did with the store. Since there may be a few entries with the same index value (if it's not unique) we need to use IDBKeyRange. This will filter the results depending on what function you use. Here, we want to only get items by the provided band, so we used the only() method. You can also use lowerBound(), upperBound() and bound. The method names are pretty self explanatory.


Conclusion

So enabling off-line access for your users is not as complicated as it may seem. I hope that after reading this article you will make your applications more user-friendly by allowing them to access some parts (or maybe even all) of it without an Internet connection. You can download the sample app and experiment with it, adding more options or including some parts of it into your website.

Tags:

Comments

Related Articles