Platinum Partner
css,html5,indexeddb

IndexedDB in Action: Complete Sample App

After a bit more sweat and tears, I've now got a "full" (if ugly) example of an IndexedDB application. It allows you to create and delete simple notes. You can view this demo here:

http://www.raymondcamden.com/demos/2012/apr/30/test5.html

Right now this demo is Firefox only. It doesn't work in Chrome because of the bug I mentioned in my earlier blog post. Here's the code - and again - I want to mention (and credit) the excellent MDN tutorial for making this easier to build.

<!DOCTYPE html>
<html>

<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var db;

// https://developer.mozilla.org/en/IndexedDB/Using_IndexedDB
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;

$(document).ready(function() {

	var openRequest = indexedDB.open("notes",5);

		//handle setup
		openRequest.onupgradeneeded = function(e) {

			console.log("running onupgradeneeded");
			var thisDb = e.target.result;

			//temp delete
			//thisDb.deleteObjectStore("note");

			//Create Note
			if(!thisDb.objectStoreNames.contains("note")) {
				console.log("I need to make the note objectstore");
				var objectStore = thisDb.createObjectStore("note", { keyPath: "id", autoIncrement:true });  
				objectStore.createIndex("title", "title", { unique: false });
			}


		}

		openRequest.onsuccess = function(e) {
			db = e.target.result;

			db.onerror = function(event) {
			  // Generic error handler for all errors targeted at this database's
			  // requests!
			  alert("Database error: " + event.target.errorCode);
			  console.dir(event.target);
			};

			displayNotes();

		}

		function displayNotes() {

			var transaction = db.transaction(["note"], IDBTransaction.READ);  
			var content="<ul>";

			transaction.oncomplete = function(event) {
	  			console.log("All done!");
	  			$("#noteList").html(content);
			};

			transaction.onerror = function(event) {
			  // Don't forget to handle errors!
			  console.dir(event);
			};

			var objectStore = transaction.objectStore("note");

			objectStore.openCursor().onsuccess = function(event) {  
			  var cursor = event.target.result;  
			  if (cursor) {  
			  	content += "<li data-key=\""+cursor.key+"\"><span class=\"label\">"+cursor.value.title+"</span>";
			  	content += " <a class=\"delete\">[Delete]</a>";
			  	content +="</li>";
			    cursor.continue();  
			  }  
			  else {  
			  	content += "</ul>";
			  	console.log("Done with cursor");
			  }  
			};  

		}

		$("#noteList").on("click", "a.delete", function(e) {
			e.preventDefault();
			var thisId = $(this).parent().data("key");
			console.log("delete "+thisId);

			var request = db.transaction(["note"], IDBTransaction.READ_WRITE)  
			                .objectStore("note")  
			                .delete(thisId);  
			request.onsuccess = function(event) {  
				displayNotes();
			};  

			return false;
		});

		$("#noteList").on("click", "li", function() {
			var thisId = $(this).data("key");
			var transaction = db.transaction(["note"]);  
			var objectStore = transaction.objectStore("note");  
			var request = objectStore.get(thisId);  
			request.onerror = function(event) {  
			  console.dir(event);
			};  
			request.onsuccess = function(event) {  
			  var note = request.result;
			  $("#noteDetail").html("<h2>"+note.title+"</h2><p>"+note.body+"</p>");
			};  
		});

		//TEMP TO REMOVE
		$("#addNoteButton").click(function() {

			var title = $("#title").val();
			var body = $("#body").val();
			
			var request = db.transaction(["note"], IDBTransaction.READ_WRITE)
							.objectStore("note")
							.add({title:title,body:body});

			request.onsuccess = function(event) {
				$("#title").val("");
				$("#body").val("");
				displayNotes();
			};

			return false;
		});

});

</script>
<style>
#noteList li span.label {
	cursor:pointer;
}
a.delete {
	color:red;
	font-size:.6em;
	cursor: pointer;
}
</style>
</head>

<body>

	<h2>Notes</h2>

	<div id="noteList"></div>
	<div id="noteDetail"></div>

	<h2>Add Note</h2>
	<form>
	<input type="text" id="title" placeholder="Title" required><br/>
	<textarea id="body" placeholder="Enter body here..." required></textarea>
	<p>
	<button id="addNoteButton">Save Note</button>
	</p>
	</form>

</body>
</html>

Nothing too scary, right? Using method chaining makes the code a bit more palatable and simpler to work with.

After getting this working, I began to look at how you can retrieve data. I guess I shouldn't be surprised (and @thefalken pointed it out to me), but you are limited to primary key lookups only.

So let me make sure that is clear. This is not a replacement for WebSQL. You cannot search. I guess - technically - you could search if you load everything up and iterate over it, but that's not really efficient. You can do range based filters, so for example, given a set of names I could go from Bob to Mary, but if I wanted to quickly find all the objects with property X set to Y and property Z set to A, then I'm out of luck. I was really thinking this was a Mongo-ish type solution, but I was wrong.

I don't know about you - but this is kind of disappointing. Maybe my opinion will change, but right now I'm sad that WebSQL is being dumped for this.

 

Published at DZone with permission of {{ articles[0].authors[0].realName }}, DZone MVB. (source)

Opinions expressed by DZone contributors are their own.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}