Indexed Database (IndexedDB) is an API for storing data at client side and a proposed standard, still in the relatively early stages of development. With the IndexedDB API, developers can store data objects within the user’s browser. In this tutorial series we will explore the basics of this emerging technology by building a simple note-keeping facility for a Web page or site. Users will be able to add and delete notes, with past notes automatically displaying when the user revisits. The notes are private to the user as they are stored locally. A typical use for this utility could be on a site with informational content, such as educational material.
At the time of writing, browser support is varied – IndexedDB itself is supported by Firefox 4+, Chrome 11+ and the forthcoming Internet Explorer 10. However, readers should note that we will be using methods in this tutorial series that are not currently supported by Chrome (specifically the “onupgradeneeded” method in part 2). It goes without saying that IndexedDB is not a feature you can rely on yet, but it is hoped that Chrome and other browsers will be improving support in the near future. In these tutorials we will be getting to grips with the technology from an educational point of view, but in any live sites you are working on, make sure you don’t use IndexedDB for vital functions just yet.
This series is in four parts:
- Setup and opening the note database
- Creating the object store
- Adding and deleting notes
- Querying and presenting notes
The following image should give you an idea what we’re building (pictured in Firefox):
Create the Page
Let’s use an HTML5 page outline as follows:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
</style>
<script type="text/javascript">
</script>
</head>
<body>
</body>
</html>
We will be adding code to the body, script and style sections throughout the series. First, add two sections in the page body:
<div id="content">
<h2>Page Content</h2>
</div>
<div id="note_col">
<h2>Your Notes</h2>
</div>
The left side of the page will include the page content, with the note section on the right. Inside the content section add anything you like after the heading, e.g.:
<p>Here is the page content</p>
In the “note_col” div, after the heading, add the following element:
<div id="notes">
</div>
This is where the notes will be displayed. At the moment it is empty, but our JavaScript code will add elements to this when the user creates notes. Next, still inside the “note_col” element, add the following section to capture user note input:
<div id="add">Add a new note:<br/>
<textarea id="note_in" rows="5" cols="30"></textarea><br/>
<input type="button" value="add" onclick="addNote()"/>
</div>
Take a moment to look over this code. We use a textarea to capture the user note text, with the button calling a JavaScript function we will add later.
Style the Elements
Let’s add some CSS for the initial appearance of these elements. In the style section of your page head, add the following section to apply general styling to the page body:
body {
font-family:sans-serif;
color:#333333;
font-size:small;
background-color: #ccccff;
background-image: -moz-linear-gradient(top, #ababff, #dedeff);
background-image: -webkit-linear-gradient(top, #ababff, #dedeff);
background-image: -o-linear-gradient(top, #ababff, #dedeff);
background-image: -ms-linear-gradient(top, #ababff, #dedeff);
background-repeat:no-repeat;
}
You can of course alter the style if you like – we are using a CSS3 gradient for the page background. Next in the style section, add properties for the content section of the page:
/*content section*/
#content {
width:75%;
float:left;
background:#ffffff;
box-shadow: 2px 2px 2px 2px #999999;
padding:20px;
margin-bottom:10px;
}
We use a CSS3 box shadow around the main page content and specify that the content will occupy three quarters of the page width. Next style the note column:
/*note section*/
#note_col {
width:20%;
float:right;
}
This will appear to the right of the main page content for the user to capture their notes, comments and thoughts. Now add some styling for the content of the note column:
/*add a note section*/
#add {
margin:10px;
margin-top:20px;
}
/*note heading*/
#note_col h2 {
padding-left:10px;
}
These two sections simply keep the elements aligned clearly, but you can apply whatever design you like. Later we will add styling for the notes themselves.
Setup IndexedDB
Let’s now get started on the IndexedDB itself. In the script section in your page head, start by handling browser differences:
//take care of browser prefixes
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
Although not all of the browsers are going to support all of the code we will be using here straight away, they may do so at some point in the future, so we set the code up to be ready for them. This simply instructs the script to use whichever vendor-specific version of the Indexed Database API is available. Now create some variables:
//database variables
var noteDB;
var noteRequest;
var noteTransaction;
var noteObjectStore;
We will be using these variables throughout the script, although the objects stored within them will sometimes be recreated. The database object will be returned when we attempt to open or create the database, and will be used for all of the database functions. The request object represents a request for some operation to be carried out, such as querying or inserting data. The transaction object is used whenever we read from or write to the database. Finally the object store represents the structured data itself, i.e. the content of the database.
When the user visits the page, we will need to initialize the database, so add an initialization function as follows:
function init() {
//request to open the database
noteRequest = window.indexedDB.open("KeptNotes", 1);
}
This is our request to open the database. If the database does not exist yet, this line will create it. We give the database a name and version number, assigning the result to the request object. Now we need to handle what happens when this code executes – the user will be prompted to allow or deny database storage. We need methods to handle either success or failure of this operation. Inside the init function, after the existing line, add the following two callback methods:
//error fires if user does not agree
noteRequest.onerror = function(event) {
alert("Can't open note database! " + evt.target.errorCode);
};
//success fires if user agrees
noteRequest.onsuccess = function(event) {
//initiate database
noteDB = noteRequest.result;
//call function to read existing notes and display them in the page
getNotes();
};
If there is an error or the user denies the request to store data, we output a message. If opening was a success, we carry on, assigning the database variable and calling a helper function. We will add the “getNotes” function later and will also be adding to the init function. Finally, after the init function, before the end of the script section, call the init function as follows:
//start the database once dom objects are loaded
window.addEventListener("DOMContentLoaded", init, false);
We initialize when the DOM is loaded. Keep this line at the bottom of your script section, adding any other functions above it.
Conclusion
That’s all for the first part of this series. Next we will work on creating the database object store. In parts 3 and 4 we will implement adding and deleting notes as well as presenting them back to the user. A final note on the IndexedDB to bear in mind before next time is that it is not a relational database structure. IndexedDB is a store of hierarchical objects represented as key value pairs. This requires a slight mental adjustment if you are accustomed to relational databases.