Using IndexedDB in your JavaScript/HTML5 Windows 8 Metro Apps

Building Windows 8 Metro Apps using HTML5 standards is, for the most part, a very easy process. One of the HTML5 technologies, which is very powerful but not as well understood, is the IndexedDB technology. While you may be thinking this is just another name for WebSQL (aka SQLite), it is actually something different entirely. IndexedDB is a non-relational data store designed to store JSON objects in collections known as an Object Store within a Database. Each Object Store has a single key, which can be configured to auto increment. Furthermore, the Object Store may also utilize one or more indexes defined on other fields within the object. If you are already familiar with IndexedDB for non Metro based apps, you will feel right at home as the API is unchanged.

To get us started we first need to open/create a DB for our application.

 function openAppDB(success) {
 var request = window.indexedDB.open("MyAppDb", 1);
 // Add asynchronous callback functions
 request.onerror = function () { /* Error */ };
 request.onsuccess = function (evt) { success(evt.target.result); };
 request.onupgradeneeded = function (evt) { upgradeAppDB(evt); };
 request.onblocked = function () { /* Blocked Logic */ };
 function upgradeAppDB(evt) {
 //Perform Upgrade Operations here
 var txn = evt.target.transaction;
 var objectStore = evt.target.result.createObjectStore("objstore1", { keyPath: "id", autoIncrement: true });
 objectStore.createIndex("text1", "text1", { unique: false });
 txn.oncomplete = function () { /* Upgrade Complete */ };

The code may appear a little unusual if you are not used to the asynchronous nature built into the IndexedDB API. This actually serves a very important purpose as it reduces the amount of time the main thread is blocked. Within the openAppDB method, it starts off by calling window.indexedDB.open with the name of the DB and the desired version number. Next we provide a function for the various events, onerror, onsuccess, onupgradeneeded and onblocked. For the sample code, only two of the events are populated. When the database being opened is an older version (or new), the upgradeAppDB method will be called. Within this method we start off by grabbing a reference to the transaction and call createObjectStore to create our first Object Store within the database. Next the method adds a single index on the text1 field. Back to the openAppDB for the onsuccess event. Within the open event, it calls the method passed in at the start. In this instance is another method called AddMethods shown below. This technique of passing callback method is a good technique that helps to provide structure to asynchronous operations such as these.

 function AddRecords(db)
 //Start a transaction
 var txn = db.transaction("objstore1", "readwrite");
 txn.oncomplete = function () { /* Transaction Complete */ };
 txn.onerror = function () { /* Transaction Error */ };
 txn.onabort = function () { /* Transaction Aborted */ };
 //Open the Object Store objstore1
 var objstore = txn.objectStore("objstore1");
 var data = {
 "text1": "Text Value",
 "DateTime": new Date()
 var request = objstore.put(data);
 request.onsuccess = function (e) { /* Changes Committed Successfully*/ }; ;
 request.onerror = function (e) { /* Error */ };

Again, the AddRecords method will be called upon completion of opening the DB. As you can see we start with creating a transaction on one or more Object Stores in either read only or Read/Write. After the transaction event handlers, the code then opens the object store objstore1. Next a simple data object is created with two fields, text1 and DateTime. To add the records to the Object Store the data object is passed to the put method. The put operation is again an asynchronous operation, which includes onsuccess and onerror events. At this point the transaction will then finish and commit all changes to the database. To retrieve records from the database, we will reuse the openAppDB shown above, but pass in another callback method as shown below.

 function ReadRecords(db) {
 var txn = db.transaction("objstore1", "readwrite");
 txn.oncomplete = function () { /* Transaction Complete */ };
 txn.onerror = function () { /* Transaction Error */ };
 txn.onabort = function () { /* Transaction Aborted */ };
 //Open the Object Store objstore1
 var objstore = txn.objectStore("objstore1");
 var index = objstore.index("text1");
 index.get("Text Value").onsuccess = function (evt) {
 var res = evt.target.result;

By using a different call back for the openAppDB, as shown in the first line above, we can reuse any code built to create/upgrade the database and Object Stores as well as initial error handling. Within the ReadRecords method, we create a new transaction for objstore1 with the transaction event handlers. Then we create a reference to the objstore1 for the transaction. We could at this point call the get method on the Object Store with a key value; however, we can go one step further and make use of the index we created previously. By creating a reference to the index we can perform simple searches (exact match) using the get method based upon a non-key field. One downside to this approach is that it will only return a single record, which matches the search phrase provided. To perform more complicated search operations or return additional matching records we will need to use a cursor on the index.


As you can see, the IndexedDB API is a bit different, but not all that difficult. If you have never used a non-relational database before you will need to spend a little bit of time rethinking how you want to store the data and interconnect it. Even with these minor differences to get use too, IndexedDB is a very power database storage mechanism, which will soon be widely used across HTML5 apps.

This article was originally published on August 24th, 2012

Related Articles

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date