- Tutorials / JavaScript
- Sunday, 23rd Dec, 2012
Home » Tutorials » JavaScript » HTML5 Storage: IndexedDB (Simple Easy to Understand)
The IndexedDB Database or better known it as IndexedDB, a new HTML5 web database that allows our HTML5 web application to store data inside a user’s browser. Unlike HTML5 localstorage which lets us store data using a simple key-value pair only, the IndexedDB is more powerful and useful for applications that requires to store a large amount of data. In addition, with its rich queries abilities, these applications can load faster and more responsive than ever.
The W3C has announced that the Web SQL database (another option of HTML5 storage) is a deprecated specification, and web developers should not use the technology anymore. Instead, web developers should use the replacement – IndexedDB, a new HTML5 data storage to manipulate their data on client-side.
Following decribes exactly what you will learn in this article:
Please check out the demo before we start the tutorial.
Since we know that the IndexedDB API is still evolve, so we need to include the following prefixes of implementation. Besides, for best practice, we should always provide fallback content for unsupported browsers.
//prefixes of implementation that we want to test window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!window.indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") }
Before we create the database, the very first thing to do is to prepare some data for the database. Let say we have some customer information as shown below:
const customerData = [ { id: "00-01", name: "Bill", age: 35, email: "bill@company.com" }, { id: "00-02", name: "Donna", age: 32, email: "donna@home.org" } ];
2 data enetries, each entry consists of the information of ID, name, age and email of the customer.
Before we can insert the data into the database, we need to open our database using the open() method as shown below:
var db; var request = window.indexedDB.open("newDatabase", 1); request.onerror = function(event) { console.log("error: "); }; request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; request.onupgradeneeded = function(event) { }
As you can see we have opened a database with the name “newDatabase” and the version of the database. All IndexedDB databases are stored in the same origin with the web application / website. Example, if myblog.com might has a database named “newDatabase” and mybusiness.com also might has a totally distinct database named “newDatabase”.
The open() method has accepts 2 parameters, the first is the name ofthe database. It will checks whether the database named “newDatabase” is already exist or not, if it is exist, then it will open the database, else it will create a new one. The second paramter of open() method is the version of the database, which allows you to update the schema of the database.
If everything succeeds, then a success event “onsuccess” is fired with request as its target and we have save the request’s result for later use by assigning it to db variable.
If the process of opening database fail, then an error event “onerror” is fired.
If you want to update the database, or to create, delete or modify the database, then you have to implement the onupgradeneeded handler or which will be called as part of a versionchange transaction that allows you to make any changes on the database. Please bear in mind that, the “onupgradeneeded” handler is the only place for you to alter the structure of database.
Again, IndexedDB is NOT same as a Relational Database. IndexedDB uses object stores to store data rather than tables. Whenever a value is stored in an object store, it is associated with a key. The interesting of IndexedDB is it allows us to create indices on any object store. An index lets us to access the values stored in object store using the value of a property of the stored object. This may sound confusing now, but you may know it better after go through the entire lesson.
The following code illustrates how we create the object store and insert the pre-prepared data into it:
request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("customers", {keyPath: "id"}); for (var i in customerData) { objectStore.add(customerData[i]); } }
We create an object store using createObjectStore() method. This method accepts 2 parameters: – name of the store and a parameter object. In this case, we have named the object store as “customers” and defined a keyPath that is the property that makes an individual object in the store unique. In this example, we have use the “id” as keyPath, which is unique value in the object store, and you must make sure that the “id” property must be present in every objects in the object store.
Once the object store is created, we can start adding the data into it using for loop.
You may probably want to manually add extra data into the database, then here is how you should write the function:
function add() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .add({ id: "00-03", name: "Kenny", age: 19, email: "kenny@planet.org" }); request.onsuccess = function(event) { alert("Kenny has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nKenny is aready exist in your database! "); } }
We have just manually added a new data named with “Kenny” to the object store “customer” using add() method.
Before we can do anything (read, write, modify) to our database, we have to start use a transaction. The transaction() method is used to specify which object stores you want the transaction to span. The transaction() mthod accepts 3 parameters (second and third are optional): – First is the list of object store you want to deal with, second is whether you want to read only or read and write to the object, third is the versionchange.
The transaction method let you have the object store that you specified and insert, modify or delete the data that you need. In this case, we insert the data using add() method.
Let’s retrieve the data from the database. We can retrieve the data using get() method.
function read() { var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { // Do something with the request.result! if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; }
We use get() method to retrieve the data we need from object store. Since we already set the id of object as keyPath earlier, so the get() method will look up the object that has the same id value. This will return us the object named “Kenny”which is the object that we manually added in the previous function.
If you want get all data instead of one from object store, then you may need to use a cursor. Here is another function that using cursor to retrieve all data from object store:
function readAll() { var objectStore = db.transaction("customers").objectStore("customers"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; }
As you can see, we implement the openCursor() method to accomplish the goal. The openCursor() is used to iterate over multiple records in a database. It can accepts several parameters, such as limit the range items, the direction that we want to iterate and etc. In this case, we leave it no parameters.
The cursor object itself is the result of the request. We have implement the continue() function to continues with the next iteration in the loop. When the loop reached end, then we will get the alert with content “No more entries!”.
Removing data from object store is very similar to other functions that we have just learnt. Here is how the code looks like:
function remove() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .delete("00-03"); request.onsuccess = function(event) { alert("Kenny's entry has been removed from your database."); }; }
If you want to remove data from object store, then you may need to use delete() method. You have to pass the keyPath of the object that you want to remove as paramter to the delete() method. In this case, we remove the object with named “Kenny” which we added via add function just now.
We have just wrote all the functions, and now is the time to display the data using the onclick event that binded to HTML button.
<!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>IndexedDb Demo | onlyWebPro.com</title> </head> <body> <button onclick="read()">Read single data from indexedDb</button> <button onclick="readAll()">Read all data from indexedDb</button> <button onclick="add()">Add data to indexedDb</button> <button onclick="remove()">Delete data from indexedDb</button> </body> </html>
We have prepared 4 HTML buttons. Each of the button is used to trigger the Javascript function that we wrote earlier in this article. Save your document and view it in supported browser. Have fun! 🙂
<!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>IndexedDb Demo | onlyWebPro.com</title> <script type="text/javascript"> //prefixes of implementation that we want to test window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!window.indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") } const customerData = [ { id: "00-01", name: "Bill", age: 35, email: "bill@company.com" }, { id: "00-02", name: "Donna", age: 32, email: "donna@home.org" } ]; var db; var request = window.indexedDB.open("newDatabase", 1); request.onerror = function(event) { console.log("error: "); }; request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("customers", {keyPath: "id"}); for (var i in customerData) { objectStore.add(customerData[i]); } } function read() { var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { // Do something with the request.result! if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; } function readAll() { var objectStore = db.transaction("customers").objectStore("customers"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; } function add() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .add({ id: "00-03", name: "Kenny", age: 19, email: "kenny@planet.org" }); request.onsuccess = function(event) { alert("Kenny has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nKenny is aready exist in your database! "); } } function remove() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .delete("00-03"); request.onsuccess = function(event) { alert("Kenny's entry has been removed from your database."); }; } </script> </head> <body> <button onclick="read()">Read single data from indexedDb</button> <button onclick="readAll()">Read all data from indexedDb</button> <button onclick="add()">Add data to indexedDb</button> <button onclick="remove()">Delete data from indexedDb</button> </body> </html>
The HTML5 IndexedDB API is very useful and powerful. You can leverage it to create rich, online and offline HTML5 application. In addition, with IndexedDB API, you can cache data to make traditional web applications especially mobile web applications load faster and more responsive without need to retrieve data from the web server each time.