Firefox OS Tutorial : Episode 7 : Storage using IndexedDB

Welcome to Episode 7 of the Firefox OS Tutorial. In the previous episode, we looked at how you could add persistence to your application via the localStorage API. As the objects that you want to persist become more complicated, you can use another HTML5 API called IndexedDB API, which lets you store complex objects.

Prerequisites

  • You have setup your machine with the Firefox OS Simulator. If not, you can check out Episode 1, which takes you through the entire setup.
  • You have a basic understanding of writing Firefox OS Apps. If not, I strongly suggest to refer to earlier episodes, especially Episode 2, that covers how to write your first Firefox OS App.

What this Episode covers

  • What is the HTML5 IndexedDB API
  • Sample Firefox OS Application that covers using HTML5 IndexedDB API. We shall be extending the same Notes application that we wrote earlier. We will replace the localStorage API calls with the IndexedDB API calls in this episode.

Episode 7 in Action

Let us check out the application in action first. The application is going to be similar to the previous one and in terms of the UI and functionality, there is no difference. But we will repeat it here for the sake of refreshing everything again.

What we shall write is a mobile application that will allow us to save some quick notes. Each note will have a title and some details. These notes will be saved in the Indexed DB of the device and then we can view all our notes too.

All right then, the first screen of the mobile app is shown below:

ep6-screen1

When we click on Add a Note button, we get a screen as shown below where we can enter the title and details for the new note. Once we are done, we can save the note by clicking on the Save Note button.

ep6-screen2

If the note is successfully saved, it will display a message as shown below:

ep6-screen3

To view all the notes, you need to click on the View Notes button from the main screen. This will retrieve all the notes from the Local Storage and display them to you in a collapsible list form.

ep6-screen4

You can click on any of the signs and it will expand to show you the note details as shown below:

ep6-screen5

If you wish to delete all the notes, there is also a Clear button. This will delete permanently all the notes from the Local Storage.

Let’s get going with the code. Note that the example screenshots are from the Firefox OS Simulator running locally. So you can use your Firefox OS Simulator to run all the examples. Alternately, you can try it on the device also.

Download Full Source Code – Episode 7

I suggest that you begin with a full download of the project source code. Since the project depends on libraries like jQuery and jQuery Mobile, it will save you the hassle of downloading the dependent libraries.

Go ahead & download the code from : https://github.com/rominirani/SaveNotesIndexedDB

Extract all the code in some folder. For e.g. on my machine, the code is present in e:\firefox-os-blog\episode7\SaveNotesIndexedDB but it could be any directory of your choice. You should see a folder structure inside of SaveNotesIndexedDB, that looks something like this:

ep6-screen9

HTML5 IndexedDB API

The HTML5 IndexedDB API is another JavaScript API that allows you to build persistence in your web applications. At the end of the day, it is similar at a high level with the localStorage API that you saw in the previous episode.

But it does have some important differences and these points will help you a bit in evaluating which way to go.

  • LocalStorage using key pairs is good for data types and objects that are simple in nature. Often as the objects that you persist get complicated, you will notice that you will have to play a lot with JSON parsing and stringifying. IndexedDB is meant to address that by allowing you to persist complex objects and even create indexes on key fields to help you retrieve easily.
  • LocalStorage API is synchronous in nature. This means that you should ensure that your API operations are quick, else you could end up blocking the User Interface. The IndexedDB API is asynchronous in nature and this means that you are not blocking your UI to complete the operation. You make the call and once it is done, the result (either onsuccess or onerror is a callback to your functions).
  • LocalStorage API is much simpler to use than IndexedDB API and which you shall see in a while but several wrappers do exist that sort of abstract out the API complexity.
  • Searching through LocalStorage API is a challenge. On the other hand, in the IndexedDB world, you can create indexes and search on them via various criteria.

Few things note about the IndexedDB API:

  • The IndexedDB API allows your application to create data stores.
  • Each datastore can be analogous to saving one type of data. For e.g. products or notes or employees, etc.
  • The store contains records of data and you can define a key for your data and the values. The key can be autogenerated or even user provided. The value will contain your object.
  • You can define one or more indexes on your data and that makes it easier to search through the data.

Save Notes IndexedDB Application

OK. Lets get going with understand the code and how the IndexedDB API has been used to persist (save) notes in our application.

SaveNotesIndexedDB Application – manifest.webapp

The first thing we should discuss is the manifest file. This should be familiar now and it has the standard attributes like name, version, etc. There is nothing special happening here.

SaveNotes Application – index.html

Next up is the index.html page and it is a simple jQuery Mobile page.

Let us discuss the index.html page in detail now:

  • We have included the script in app.js file. #Line 10
  • There are 3 pages in the mobile application : index (Line # 16), add-notes (Line #28) and view-notes (Line # 41)
  • The #index page has two buttons for Add a Note and View Notes
  • The #add-notes page has a form for entering the title (#noteTile), details (#noteDetails) and a couple of buttons for saving the note (#btnSaveNote) and clearing the fields (#btnClearNotes)
  • The #view-notes page has a button in the header to clear all notes (#clearAllNotesBtn) and it has a div area (#note-list) to display all the current notes, once we get it from IndexedDB.

SaveNotesIndexedDB Application – app.js

Let us discuss the source code in detail now since it contains the HTML5 IndexedDB JavaScript API:

  • First, the standard stuff. One Line #41, the standard jQuery ready function is fired and the first thing that we are invoking here is a call to the initializeDB() function. In this function, we shall create the database+store and get it ready for other operations.
  • Line #2, we define our db variable that will hold the connection the database that we shall use subsequently when we add records, delete records, search for records, etc.
  • The initializeDB() function is present on Line #4. 
  • We check first for IndexedDB support by checking the property indexedDB in the window object. This will typically not be needed since the support is there, but I am just showing you this in case you want to introduce this code to other browsers via your desktop web applications too. Keep in mind that this is an evolving standard and support is not fully there across all browsers. For FirefoxOS , you can rest assured that support is present.
  • Line # 13, we open our database. We are naming the database as notesdb and providing a version of the database. We go with 1. Keep in mind that the IndexedDB API is an asynchronous API, so we are defined two callbacks: onsuccess and onerror. In the onsuccess , we initialize the db variable to the database that we just opened.
  • Great. Now that we have the connection to the database, we need to create the initial object store. Think of creating the initial tables. For this we need the onupgradeneeded callback that is defined on Line #26. This function is only called when a version change occurs. We had passed the version 1 earlier and since there is no database present, it will get invoked first time and we can then create our data stores here. If you ever want to change the schema or modify the store, you should change the version number in your upgraded version of the app when you open the database as shown on Line #13
  • In Line #36, we are creating our Object Store named notes. Keep in mind that we can create more object stores but since we are just dealing with notes here, I am creating only one. Apart from the first parameter which is the store name, the second parameter is the key field for your object. We are defining it as an auto-increment field with the key name as id.
  • This completes our initialization of the database. To summarize we opened the connection to the database (notesdb) and created one object store (notes). The notes that we create in the application will be saved in the notes datastore.
  • Let us now focus on Adding or Saving the note. Line #75 – 94. Here you will notice that we first extract out the value that the user has entered for title and detail. Then on Line #80 , we first create a transaction object from the database. To create the transaction, you can provide a list of datastore names (in our case it is just one i.e. notes) and the transaction mode i.e. read or readwrite, etc. Since we want to write a new record, we are using the readwrite mode.
  • On Line #82-85, we are creating the standard Notes object. We store the attributes for title and details.
  • Now within the transaction context, we obtain the store that we want to work with on Line # 87 and then add the object to it. We use the onsuccess and onerror callbacks as needed.
  • Now let us focus on Line # 50-73.  Line #50 – 52 indicates that when we press the View Notes button on the index page, it will navigate to the view-notes page.
  • We clear the content i.e. any existing items that were present on the page by clearing the html content for #note-list on Line #53
  • Then once again we obtain the transaction object from the database. This time we pass only the list of datastore names (in our case just notes). If you do not provide the second parameter i.e. transaction mode, it means that it is read mode. We then object the store from the transaction context on #Line 56. 
  • Next we use a cursor to iterate through each of the notes object and build out the notes HTMLElement that we shall create for each note. Notice the use of cursor.continue() on Line #69 to move to the next record.
  • Then for each note, we are simply creating a collapsible div for jQuery Mobile UI and appending it to the #note-list element.
  • Clearing (Deleting) all the notes is also straightforward. Refer to Line #103 – 116. The pattern of usage is the same. Get the Transaction. Get the Store. And then call the clear() function on the store.

Local Installation and Testing

This completes our discussion of writing Firefox OS applications that utilize the HTML5 IndexedDB API. Now comes the part of seeing it actually work. All we need to test out this application is:

  1. You should have installed the Firefox OS Simulator add-on in your Firefox Browser.
  2. A working internet connection from your machine.
  3. You should have downloaded/written the application as described above. We will assume that the index.html and manifest.webapp file are present in a folder named SaveNotesIndexedDB. You should navigate to your own directory structure when called to later.

Steps to install the application in your Firefox OS Simulator should be familiar to you now. Simply launch the Firefox OS Simulator in your Firefox Browser. From the Dashboard, click on the Add Directory button and point it to the manifest.webapp file for the SaveNotesIndexedDB application. On successful validation, the application will be installed and it will come up in your OS Simulator. For sample screenshots, refer to the section at the beginning of this blog post for Episode 7 in Action.

Next Steps

I encourage you to learn more about the Indexed DB API. Mozilla covers this in a lot more detail. A good exercise to try out would be to come up with your own little database design. Come up with a db and some data stores. Create some indexes and play around with basic CRUD Operations.

Coming up Next

The next episode will cover Web Activities, which are standard ways to invoke functionality that is already present on the device via inbuilt application or other 3rd party applications. Example of Web Activities include making a phone call, sending SMS, viewing a web page, etc. Stay tuned.

Till the next time, stay tuned and give me feedback.

Complete Firefox OS Tutorial

Feedback

I would love to hear your feedback on the series so far. Do put your feedback in the comments. If you are facing issues, use the comments to let me know about it, I will do my best to answer your queries. And by putting in your issues within this thread itself, it will help build collective knowledge that could help other readers.


Firefox OS

Advertisements

11 thoughts on “Firefox OS Tutorial : Episode 7 : Storage using IndexedDB

  1. Hi rominirani,

    I have a error message when running the code:
    var transaction = db.transaction([ ‘notes’ ], ‘readwrite’); (line #81)

    The error message:
    NotFoundError: The operation failed because the requested database object could not be found. For example, an object store did not exist but was being opened.

    I have read the document at:
    http://www.w3.org/TR/IndexedDB/#widl-IDBDatabase-transaction-IDBTransaction-DOMString-sequence-DOMString–storeNames-IDBTransactionMode-mode

    The document said: “If any of the names in storeNames do not exist in this database, the implementation MUST throw a DOMException of type NotFoundError.”
    “any of the names in storeNames” is the first argument of transaction function ([ ‘notes’ ]).
    Thus, the argument [ ‘notes’ ] does not exist in the database ‘db’ in this case.

    Could you explain me why my code don’t work? I tried step by step as this tutorial.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s