IndexedDB is a persistent object data store in the browser. Although it is not a full SQL implementation and it is more complex than the unstructured key–value pairs in localStorage, you can use it to define an API that provides the ability to read and write key–value objects as structured JavaScript objects, and an indexing system that facilitates filtering and lookup.
For this hack we will use IndexedDB to store milestone objects for a calendar application. The UI will provide a simple means to create a new milestone and provide a title, start date, and end date. The calendar will then update to show the contents of the local data store. Figure 6-8 shows the result.
Figure 6-8. FullCalendar.js and IndexedDB
We need to start by including the markup for the two pieces of the UI: the calendar and the form. We’ll begin with the form. You may notice that the input fields for the dates include data-date-format attributes. We will use these later for the JavaScript date pickers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
The calendar is provided by FullCalendar.js, a fantastic jQuery plug-in for generating robust calendars from event sources. The library will generate a calendar from a configuration object and a simple div.
1
|
|
And we can’t forget to include a few dependencies:
1 2 3 4 5 6 |
|
To improve the user experience, we will also include date pickers for choosing the dates within the form fields for start and end dates (see Figure 6-9).
Figure 6-9. Date pickers
To instantiate the date pickers we will include the following toward the beginning of our script:
1 2 3 4 |
|
The Milestone IndexedDB
Now we will set up a global namespace to hold our code, and set up a public milestones array (within the namespace) to hold our milestones temporarily while we pass them between our database and the FullCalendar API. This should make more sense as you continue to read. While we are at it we will need to normalize our indexedDB variable across all of the vendor-specific properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
This will obviously fail for now, but as you can see the initialization begins by calling the open() method on an html5hacks.indexedDB. So let’s take a closer look at open():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
First, we need to open the database and pass a name. If the database successfully opens and a connection is made, the onsuccess() callback will be fired.
Within the onsuccess, we then check for a version and call setVersion() if one does not exist. Then we will call createObjectStore() and pass a unique timestamp within the keypath property.
Finally, we call init() to build the calendar and attach the events present in the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
At this point we are poised to retrieve all the data from the database and populate our calendar with milestones. First, we declare the type of transaction to be a READ_WRITE, set a reference to the datastore, set a keyrange, and define a cursorRequest by calling openCursor and passing in the keyrange. By passing in a 0, we ensure that we retrieve all the values greater than zero. Since our key was a timestamp, this will ensure we retrieve all the records.
Once the onsuccess event is fired, we begin to iterate through the records and push the milestone objects to buildMilestoneArray:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Adding Milestones
Now that we are initializing and building our calendar, we need to begin adding milestones to the database via the form. First let’s use jQuery to set up our form to pass a serialized data object to addMilestone() on each submission:
1 2 3 4 5 6 7 |
|
Now let’s submit a few events and then view them in the Chrome Inspector to ensure they are there (see Figure 6-10).
Figure 6-10. Viewing milestone objects in the Chrome Inspector
Let’s take a closer look at our addMilestone method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
We established our read/write connection in much the same way as our html5hacks.indexedDB.init(), but now, instead of only reading data, we write a data object to the data store each time by calling store.put() and passing it data. On the onsuccess we then can call fullcalendar’s addEventSource() and pass it the data wrapped in an array object. Note that it is necessary to transform the data object into an array since that is what the FullCalendar API expects.