Create a User Note-Keeping Utility For Your Site With IndexedDB: Part 4

Oct 15, 2012
HTML5 JavaScript
By

In this series we have been building the elements of a user note-keeping utility for Web pages, using the IndexedDB API. So far we have built the database, created an object store to save the user’s notes and handled adding and deleting notes. In this last part of the series we will bring these elements together by querying the note database, presenting the user notes within the page markup so that they can see them on returning to the page. This is the final part in a series of four tutorials:

  1. Setup and opening the note database
  2. Creating the object store
  3. Adding and deleting notes
  4. Querying and presenting notes

Fetch the Stored Notes

As you may remember from the previous parts in this series, our JavaScript code calls a function named “getNotes” in various places: when a note is added or deleted and when the page is initially presented. This function is going to handle querying the object store for notes already saved, then building this data into HTML elements to include in the page markup. Add the function outline in the script section of your page head, before the line in which the “init” function is called, which should be the final line in the script:

/*
Function checks if there are existing notes and if so presents them within the page
- function is called after database initialization and when notes are added/ deleted
*/
function getNotes() { 

}

Inside the function, start by retrieving a reference to the database object store:

//get the object store
noteObjectStore = noteDB.transaction("notes").objectStore("notes");

Now get a reference to the page element in which our notes are going to appear:

//get the page element in which the note elements will appear
var noteContainer = document.getElementById("notes");

Remember that we added this element in the first part of the series. Each time this function is called it is going to clear any currently displayed notes and start from scratch, so that it can go through the same process if a note has been added or deleted. Start the content at empty:

//set to empty at first - in case a note has been deleted
noteContainer.innerHTML="";

Traverse the Notes

With IndexedDB, rather than using SQL queries, we traverse the data items using a cursor. Still inside the function, add the following section to open the cursor:

//open the cursor to traverse existing notes
noteObjectStore.openCursor().onsuccess = function(event) {

};

The remainder of the JavaScript function will be placed inside this block. If the cursor opening process is successful, the code inside this will execute. Attempt to retrieve the result of opening the cursor:

//attempt to traverse
var cursor = event.target.result;
if (cursor) {

}

The content of this “if” statement is going to execute once for each item encountered by the cursor, i.e. each note saved.

Build Each Note

For each note, we need to build an HTML element, which is in turn going to contain child elements. The entire note will be displayed as a div, so start inside the conditional statement by creating this element:

//create a new note div element
var newDiv = document.createElement("div");
newDiv.setAttribute("class", "note");

The class attribute will allow us to style the notes. Next let’s build a paragraph to display the note date:

//create paragraph for date part of note
var datePara = document.createElement("p");

Now get the date stored from the database cursor, building it into a text node:

var dateContent = document.createTextNode(cursor.value.when);//value from cursor

Remember that each note object has a field named “when” indicating the date the note was created. Now we want this to be in bold, so create a strong element:

var strongElement = document.createElement("strong");

Now we can append the text node to the strong element and the strong element to the containing paragraph:

strongElement.appendChild(dateContent);
datePara.appendChild(strongElement);

Now we can create another paragraph element for the note content itself:

//create paragraph for text part of note
var textPara = document.createElement("p");

Create a text note containing this data from the cursor:

var textContent = document.createTextNode(cursor.value.text);//value from cursor

Remember that the text is saved in each item in the database with “text” as its name. Append this text node to the paragraph element:

textPara.appendChild(textContent);

Within each note, we want to provide a delete button so that users can remove any notes they no longer want. Still inside the “if” statement, start building this interactive section:

//create paragraph with button element for deleting this note
var inputPara = document.createElement("p");
inputPara.setAttribute("class", "deletePara");

We will use the class attribute for styling. Now create the delete button:

var deleteButton = document.createElement("input");
deleteButton.setAttribute("type", "button");
deleteButton.setAttribute("onclick", "deleteNote("+cursor.key+")");//pass note key when deleting
deleteButton.setAttribute("value", "delete");

Pay particular attention to the line in which the click event listener is added to the button. The “deleteNote” function we created last time is called here, passing the key for this note as retrieved from the cursor. Now add the button to its containing element:

inputPara.appendChild(deleteButton);

Now we can append the date, note text and delete button sections to the parent note element:

//add the elements
newDiv.appendChild(datePara);
newDiv.appendChild(textPara);
newDiv.appendChild(inputPara);

Now add the parent note element to the page:

//add this note to the page
noteContainer.appendChild(newDiv);

That’s the process for the current note complete, but we want the cursor to keep traversing the object store until it finishes the notes:

//carry on to the next note if there is one
cursor.continue();

This should be the last line inside the “if” statement, which will execute once for each note data item the cursor encounters in the object store. That’s the JavaScript complete, so take a moment to look over it.

Style the Notes

The only remaining step is to make the note sections look like notes. In the style section in your page head, add styling for the note elements:

.note {
margin:10px;
box-shadow:3px 3px 3px 3px #666666;
border:1px solid #cccccc;
padding:10px;
background-color: #ffff99;
background-image: -webkit-linear-gradient(top, #ffff33, #ffff99);
background-image: -moz-linear-gradient(top, #ffff33, #ffff99);
background-image: -ms-linear-gradient(top, #ffff33, #ffff99);
background-image: -o-linear-gradient(top, #ffff33, #ffff99);
color:#000033;
font-style:italic;
}

We use a CSS3 gradient to give each note the appearance of a “post-it” note. Finally, add a style section for the delete button area in each note:

/*delete button*/
.deletePara {
text-align:right;
padding-top:10px;
}

Conclusion

That’s our note-keeping facility complete so you can save your page, upload it to a server and browse to it in order to test it. Remember that these functions will currently only function correctly in recent versions of Firefox and Chrome. Test your page by adding and deleting notes, browsing away from the page and back to see that the notes persist. If you want to explore using IndexedDB further, one area to consider looking into is using the indices we created for searching functions. Although it is still early days, you can see how APIs like IndexedDB fit into the improved local storage model we can look forward to with HTML5.

Author: Sue Smith
Sue Smith works as a Web/ software developer and technical writer based in the UK: see benormal.info for details. Sue has written for various clients including Smashing Magazine and Mobiletuts+. She also does a little Android development and some comedy writing.