Saving To-Do List Items with a Client-Side Database

Saving To-Do List Items with a Client-Side Database

In this exercise, we will use the Web SQL Database API to save to-do list items to a client-side database for later use. We will work with the methods outlined previously to do this.

Begin by creating a submodule called TODOLIST.Storage in your JavaScript application code. This module will be responsible for handling interaction with the database for the application. It is important to encapsulate this functionality, as it gives you the option to use an alternative storage mechanism (e.g., the Web Storage API) at a later date without affecting the rest of the application code.

The following code should be added to the module definition in the todolist.js file (remember to include a comma if this isn’t the last member of the module array):

Storage: (function() { // open/create a database for the application (expected size ~ 100K) var db = openDatabase("todolist", "1.0", "To Do List Database", 100 * 1024);

// check that we have the required tables created db.transaction(function(transaction) {

transaction.executeSql( "CREATE TABLE IF NOT EXISTS task(" + " name TEXT NOT NULL, " + " description TEXT, " + " due DATETIME);");

return { saveTask: function(task, callback) { db.transaction(function(transaction) { transaction.executeSql( "INSERT INTO task(name, description, due) VALUES (?, ?, ?);", [task.name, task.description, task.due]

At this stage, TODOLIST.Storage has only two functions:

CHAPTER 3: HTML5 Storage APIs

To create/open a client-side database called todolist, and to ensure that the required task table exists, creating it if required

To save a to-do list item into the task table We then create what might be called a DTO (data transfer object) or POJO (plain-old

Java object) in other languages to capture the details of a to-do list item. In future exercises, we will refer to these as POJOs, since the acronym works almost as well for JavaScript as it does for Java.

As per the preceding Storage code, Task is added to the module definition of todolist.js:

Task: function(params) { params = jQuery.extend({ name: "", description: "", due: null

}, params);

// initialize self var self = {

id: null, name: params.name, description: params.description, due: params.due ? new Date(params.due) : null

return self; }

NOTE: While we have a preference for using POJOs to capture details about an object in our application, this isn’t always the best way to go. You can see in the preceding case that Task adds very little extra value in this early stage. Personally, we find that architecting an application in this way provides some benefits once it reaches a certain size and complexity, but can feel like a waste of time initially.

When it comes to actually saving Task, we’ll provide an alternative implementation that will work without the POJO if that is your preference.

One final piece of supporting code is required and, if you have worked with jQuery and web apps before, you have probably built something like this yourself previously. To save yourself from writing the same code time and time again to extract form values from a form and map them into an object, you can use something like the following code to make that process more streamlined (given that you are able to use consistent naming for form fields, object properties, etc.).

The following code should be added to the module definition for the prowebapps.js file (remember, a trailing comma may be required depending on where you add the code in the module):

58 CHAPTER 3: HTML5 Storage APIs

getFormValues: function(form) { var values = {};

// iterate through the form values using jQuery jQuery(form).find(":input").each(function() {

// get the name of the field var fieldName = this.name.replace(/^.*\[(\w+)\]$/, "$1");

// set the value for the field values[fieldName] = this.value;

return values; }

Now that all the building blocks are in place, let’s go back and change the submit handler that was left blank when we finished Chapter 2 so that it contains some code that will actually save the to-do list item:

$("#taskentry").validate({ submitHandler: function(form) { // get the values from the form in hashmap

var formValues = PROWEBAPPS.getFormValues(form);

// create a new item to save to the database

var item = new TODOLIST.Task(formValues);

// now create a new task

TODOLIST.Storage.saveTask(item);

}, showErrors: function(errorMap, errorList) {

// code from chapter 02 } });

Download from Wow! eBook <www.wowebook.com>

Saving a new to-do item is now a simple three-step process:

1. Getting the values of the fields in the form as a JavaScript key/value pair array

2. Creating a new item from those form values

3. Asking the Storage module to save the item for us Running this code on an Android handset or emulator is quite unsatisfying, as we

haven’t built our interface for displaying items yet. To get some confidence that this is actually working, let’s have a look in Chrome, using the Chrome developer tools. As outlined in Chapter 1, a WebKit-based desktop browser is an invaluable tool when it comes to debugging mobile apps—my personal preference is Chrome.

So, we provide the form some data. As shown in Figure 3–3, I am going to give myself a to-do of mowing the lawn before the end of 2011 (it’s not one of my strong points).

CHAPTER 3: HTML5 Storage APIs

Figure 3–3. The Create Task form with sample data displayed in Chrome On submitting the form, the data passes the validation checks that we set up in the last

chapter and thus proceeds to save the data according to the logic that we set up in the submit handler. Having a look in the Storage tab in the developer tools, we can see that our data was indeed saved to the local database. Figure 3–4 shows the Chrome developer tools.

60 CHAPTER 3: HTML5 Storage APIs

Figure 3–4. The new task is saved, and can be seen using the Storage inspector in the Chrome developer tools. As promised, if you are not a fan of using POJOs and the like to encapsulate data

moving around in your application, the submit handler code can be modified to the following:

$("#taskentry").validate({ submitHandler: function(form) { // get the values from the form in hashmap

var formValues = PROWEBAPPS.getFormValues(form);

// now create a new to-do list item

TODOLIST.Storage.saveTask(formValues);

}, showErrors: function(errorMap, errorList) {

// code from chapter 02 } });

As it stands with the code in the Storage module, the date is saved as entered. Figure 3–

5 shows that the database holds a value identical to what was entered, which indicates that this value is probably saved as a string.

CHAPTER 3: HTML5 Storage APIs

Figure 3–5 . The results of not converting a string to a Date object before inserting it into the database You can see the second entry has been added as is. In reality, this is also the case for

the first entry too, as what is displayed here is simply the toString representation for a JavaScript Date object (as we converted the form value to a Date in the Task POJO).

CAUTION: The preceding behavior is interesting, given that we explicitly defined the due field as

a DATETIME type in our CREATE TABLE statement. While this won’t cause any real issues in our application here, we think it is worth noting that with current implementations of the SQL Web Database you may need to test your data on read operations in addition to writes, as you may not

be able to trust that the data in the database is of the type you expect. To confirm this behavior, try tweaking the code to see if you can actually push a string value into

the due field. You will find that you can. This appears to be consistent with the way SQLite handles DATETIME columns. For more information, check out the following URL on the SQLite site: www.sqlite.org/datatype3.html.

62 CHAPTER 3: HTML5 Storage APIs