What is Indexed DB
HTML5 brought lots of capabilities to the browsers including some storage APIs. One of the storage options available on browsers today is Indexed DB. As the name itself suggests, Indexed DB is much like a database, but it is meant to store JavaScript objects. Data in the Indexed DB is not relational; it just has to follow a definite structure.
The browsers support a number of APIs to help us interact with the Index DB. Details about all of the Indexed DB API can be found on the Mozilla Developer Network. Current implementation of the APIs by the browsers may not be perfect, as most of the APIs are still under development. But, the browsers have enough support now so that we can play around. Check caniuse.com to find if your browser supports Indexed DB.
As API of the Indexed DB says, all operations performed over Indexed DB are executed asynchronously. The operations don’t let the current thread processing to wait unless the operation is finished. Instead, we need to hook-up call backs to perform actions upon success or failure of the operation.
Promises in the browser
In the latest version of JavaScript, the language got built-in support for promises. This means, we don’t need to use any of the third party libraries to prettify the asynchronous code and keep it clean from nasty call backs. As Indexed DB works asynchronously, we can use promise API to make the Indexed DB operations cleaner. Very few of the browsers support the promise API as of now. Hopefully others will join the club soon.
Using the promise API is very easy. But you need to have a good understanding of what promises are before proceeding further. Following snippet shows how to use the promise API in an asynchronous function:
Success and failure callbacks can be hooked up to the promise object returned in the above function. Following snippet shows this:
Building a todo list app
Let’s start implementing a simple todo list using Indexed DB. To store the todo items in the Indexed DB, we need to create an object store. While creating, we need to specify the version of the DB and the key property. Any object inserted into the object store must contain the key property. Following code shows how to create a DB store:
Now that the DB is opened, let’s extract all todo items (if exist) from it. The logic of fetching the items is conceptually similar to the way we do it with databases. Following are the steps:
To add a new item to the todo list, we need to invoke the put method on the store object. As mentioned earlier, key property should be present and it should be assigned with a unique value. So, we calculate value of the next id and assign it to the object.
Finally, let’s delete todo item from the list. The logic remains quite similar to that of adding a new todo. The only difference is, we need just id of the item to be deleted.
Code of the complete sample is available at this plunk: http://plnkr.co/edit/aePFAaCucAKOXbb1qL85?p=preview
Happy coding!
HTML5 brought lots of capabilities to the browsers including some storage APIs. One of the storage options available on browsers today is Indexed DB. As the name itself suggests, Indexed DB is much like a database, but it is meant to store JavaScript objects. Data in the Indexed DB is not relational; it just has to follow a definite structure.
The browsers support a number of APIs to help us interact with the Index DB. Details about all of the Indexed DB API can be found on the Mozilla Developer Network. Current implementation of the APIs by the browsers may not be perfect, as most of the APIs are still under development. But, the browsers have enough support now so that we can play around. Check caniuse.com to find if your browser supports Indexed DB.
As API of the Indexed DB says, all operations performed over Indexed DB are executed asynchronously. The operations don’t let the current thread processing to wait unless the operation is finished. Instead, we need to hook-up call backs to perform actions upon success or failure of the operation.
Promises in the browser
In the latest version of JavaScript, the language got built-in support for promises. This means, we don’t need to use any of the third party libraries to prettify the asynchronous code and keep it clean from nasty call backs. As Indexed DB works asynchronously, we can use promise API to make the Indexed DB operations cleaner. Very few of the browsers support the promise API as of now. Hopefully others will join the club soon.
Using the promise API is very easy. But you need to have a good understanding of what promises are before proceeding further. Following snippet shows how to use the promise API in an asynchronous function:
function operate(){ var promise = new Promise(resolve, reject){ if(<some condition>){ resolve(data); } else{ reject(error); } }; return promise; }
Success and failure callbacks can be hooked up to the promise object returned in the above function. Following snippet shows this:
operate().then(function(data){ //Update UI }, function(error){ //Handle the error });
Building a todo list app
Let’s start implementing a simple todo list using Indexed DB. To store the todo items in the Indexed DB, we need to create an object store. While creating, we need to specify the version of the DB and the key property. Any object inserted into the object store must contain the key property. Following code shows how to create a DB store:
var open = function(){ var version = 1; var promise = new Promise(function(resolve, reject){ //Opening the DB var request = indexedDB.open("todoData", version); //Handling onupgradeneeded //Will be called if the database is new or the version is modified request.onupgradeneeded = function(e) { db = e.target.result; e.target.transaction.onerror = indexedDB.onerror; //Deleting DB if already exists if(db.objectStoreNames.contains("todo")) { db.deleteObjectStore("todo"); } //Creating a new DB store with a paecified key property var store = db.createObjectStore("todo", {keyPath: "id"}); }; //If opening DB succeeds request.onsuccess = function(e) { db = e.target.result; resolve(); }; //If DB couldn't be opened for some reason request.onerror = function(e){ reject("Couldn't open DB"); }; }); return promise; };
Now that the DB is opened, let’s extract all todo items (if exist) from it. The logic of fetching the items is conceptually similar to the way we do it with databases. Following are the steps:
- Open a cursor for the request to fetch items from lower bound
- The items will be returned one by one. Handle appropriate call back and consolidate all the values
var getAllTodos = function() { var todosArr = []; //Creating a transaction object to perform Read/Write operations var trans = db.transaction(["todo"], "readwrite"); //Getting a reference of the todo store var store = trans.objectStore("todo"); //Wrapping all the logic inside a promise var promise = new Promise(function(resolve, reject){ //Opening a cursor to fetch items from lower bound in the DB var keyRange = IDBKeyRange.lowerBound(0); var cursorRequest = store.openCursor(keyRange); //success callback cursorRequest.onsuccess = function(e) { var result = e.target.result; //Resolving the promise with todo items when the result id empty if(result === null || result === undefined){ resolve(todosArr); } //Pushing result into the todo list else{ todosArr.push(result.value); if(result.value.id > lastIndex){ lastIndex=result.value.id; } result.continue(); } }; //Error callback cursorRequest.onerror = function(e){ reject("Couldn't fetch items from the DB"); }; }); return promise; };
To add a new item to the todo list, we need to invoke the put method on the store object. As mentioned earlier, key property should be present and it should be assigned with a unique value. So, we calculate value of the next id and assign it to the object.
var addTodo = function(todoText) { //Creating a transaction object to perform read-write operations var trans = db.transaction(["todo"], "readwrite"); var store = trans.objectStore("todo"); lastIndex++; //Wrapping logic inside a promise var promise = new Promise(function(resolve, reject){ //Sending a request to add an item var request = store.put({ "id": lastIndex, "text": todoText }); //success callback request.onsuccess = function(e) { resolve(); }; //error callback request.onerror = function(e) { console.log(e.value); reject("Couldn't add the passed item"); }; }); return promise; };
Finally, let’s delete todo item from the list. The logic remains quite similar to that of adding a new todo. The only difference is, we need just id of the item to be deleted.
var deleteTodo = function(id) { var promise = new Promise(function(resolve, reject){ var trans = db.transaction(["todo"], "readwrite"); var store = trans.objectStore("todo"); var request = store.delete(id); request.onsuccess = function(e) { resolve(); }; request.onerror = function(e) { console.log(e); reject("Couldn't delete the item"); }; }); return promise; };
Code of the complete sample is available at this plunk: http://plnkr.co/edit/aePFAaCucAKOXbb1qL85?p=preview
Happy coding!
No comments:
Post a Comment
Note: only a member of this blog may post a comment.