Friday, May 10, 2013

Introduction to IndexedDB

Today I am going to write about another storage method which is available in HTML5 as well is in Windows Store Apps which is “IndexedDB”. IndexedDB is an API for client-side storage where significant amounts of structured data can be stored. Since IndexedDB is based on indexes, it provides high performance query capability.

IndexedDB has two API modes which are Synchronous and Asynchronous. As in to the date I am writing this post, synchronous API of IndexedDB has not yet been implemented in any browser, so I will be using the asynchronous API here. We can get the asynchronous access to a database, by calling open() on the indexedDB attribute of a window object. When using asynchronous API, database operations do not execute immediately; instead operations return request objects that are executed in the background. And again IndexedDB is an event-driven API. So we can define event handlers for returned requests and then respond to success, failure etc events of those requests.

Now lets dive into see how we can use IndexedDB in a HTML5 application. I am creating a simple web applictaion to store my ToDO list.

Before creating a IndexedDB, first thing to do is check whether the browser supports IndexedDB. As in to the date I am writing this post, these are the browsers and their versions which supports IndexedDB.
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; 

if (!window.indexedDB) {
    alert("Your browser doesn't support IndexedDB");
}
After checking the browser support I can create the database.
function initDb() {
    var request = indexedDB.open("ToDoDB", 1);
    request.onsuccess = function (event) {
        db = request.result;
        showAllItems();
    };
    request.onerror = function (event) {
        console.log("IndexedDB error: " + event.target.errorCode);
    };
    request.onupgradeneeded = function (event) {
        var objectStore = event.currentTarget.result.createObjectStore("todo", { keyPath: "id", autoIncrement: true });
        objectStore.createIndex("priority", "priority", { unique: false });
        objectStore.createIndex("tododesc", "tododesc", { unique: true });
    };
}
Here indexedDB.open() accepts two parameters (database name and the version number) and returns a IDBOpenDBRequest. If the database is not there, the open() method will create a new one. When the database open request succeeds the request.onsuccess event is fired. If an error occurred, request.onerror event is fired. In the case where the database’s version is smaller then the provided version the request.upgradeneeded event will be fired and you will be able to change the database’s structure in it’s handler. In the handler we can create a objectStore. Object store holds records, which are key-value pairs. Records within an object store are sorted according to the keys. This sorting enables fast insertion, look-up, and ordered retrieval. Key paths and key generators are used to create the main index for the stored value. The key is like a primary key. Then I am creating another indexes to search my “todo” object store by “priority” and “tododesc”. In here I am putting a unique constraint to "tododesc", assuming I can’t have same "tododesc". But same priority can be there with many "tododesc".

Add New Item

function addNewItem() {
    var priority = "Normal"
    var tododesc = "My Task 1"

    var transaction = db.transaction(["todo"], "readwrite");
    var objectStore = transaction.objectStore("todo");
    var request = objectStore.add({ priority: priority, tododesc: tododesc });
    request.onsuccess = function (event) {
        alert("added");
};
Before doing anything with the database, I need to start a transaction first. Transactions come from the database object, and we have to specify which object stores I want the transaction to span. Also, I need to mention whether I am going to make changes to the database or I am just going to read from it. Then I am getting my particular object store from the transaction and I am adding a new object to it. Again it will return me a request which the events can be fired upon.

Delete Item

function deleteItem(id) {
    var transaction = db.transaction(["todo"], "readwrite");
    var objectStore = transaction.objectStore("todo");
    var request = objectStore.delete(parseInt(id));
    request.onsuccess = function (event) {
        alert("deleted");
    };
    request.onerror = function (event) {
        alert("error deleting record");
    };
}
Again it’s same as adding a new item. I am just parsing the id to delete.

Show All Items

function showAllItems() {
    var transaction = db.transaction(["todo"], "readwrite");
    var objectStore = transaction.objectStore("todo");
    var request = objectStore.openCursor();
 
    request.onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
            alert("ID: " + cursor.key + " \nPriority: " + cursor.value.priority + " \nTo Do Desc: " + cursor.value.tododesc + " ");
            cursor.continue();
        }
        else {
            // no more records
        }
    };
}
To get all the items in the object store, I can use a cursor. Cursors are used to iterate over multiple records in a database. The openCursor() function takes several arguments. First We can limit the range of items that are retrieved by using a key range object. Second, we can specify the direction that we want to iterate. Here it will be in the ascending order. Then to keep iterating, I am calling cursor.continue().

Delete Database

function deleteDb() {
    var iDb = indexedDB.deleteDatabase("ToDoDB");
    iDb.onsuccess = function (event) {
        alert("database deleted");
    };
    iDb.onerror = function (event) {
        alert("error deleting database");
    };
}
Deleting the database is pretty much straight forward. Just call the deleteDatabase of the indexedDB of a window object. You have to provide the database name, and the database will be deleted.

I am uploading a full sample to my SkyDrive so you can have a jump start on IndexedDB.

Happy Coding.

Regards,
Jaliya

Thursday, May 9, 2013

Introduction to HTML 5 Web Storage

HTML5 has introduced two mechanisms for storing structured data on the client side, similar to HTTP session cookies. HTTP cookies has some drawbacks such as limited to store 4 KB of data etc., Web storage is considered as one of the most rising data storage methods is HTML 5 web applications as well as Windows Store Apps.

Web storage consists of two main web storage types: local storage and session storage, behaving similarly to persistent cookies and session cookies respectively. These two storage types differ from each other based on it's scope and lifetime.

Local Storage

Data placed in local storage is per domain (it's available to all scripts from the domain that originally stored the data) and persists after the browser is closed. That means if you close the browser and check for the data in local storage, it will still be available. There is no expiration date for the data in local storage unless you explicitly delete them. You can access the data in the local storage, may be next day, next month or even after a year.

Session Storage

Session storage is per-page-per-window and is limited to the lifetime of the window.
Programming Web Storage
Store Item
localStorage.someid = 'somevalue';
//or
localStorage.setItem('someid', 'somevalue'); 

sessionStorage.someid = 'somevalue';
//or
sessionStorage.setItem('someid', 'somevalue');
Retrieve Item
var value = localStorage.getItem('someid');
//or
var value = localStorage.someid

var value = sessionStorage.getItem('someid');
//or
var value = sessionStorage.someid
Remove Item
localStorage.removeItem('someid');
sessionStorage.removeItem('someid');
Clear Storage
localStorage.clear();
sessionStorage.clear();
Now let’s see this in an example. In My page I am two text boxes to insert Id and value.

image
Input
First what I am doing is check whether the browser supports web storage. You can find the browsers and their versions which supports Web Storage from here.
var isWebStorageSupported = false; 

window.onload = function ()
{
    if (typeof (Storage) !== "undefined") {
        //your browser supports web storage.
        isWebStorageSupported = true;
    }
    else {
        //your browser doesn't support web storage.
        isWebStorageSupported = false;
    }
}
Now if the browser supports web storage, I am inserting values and storing these in local storage as well as in session storage.
//check whether the browser supports web storage and
//and insert to local storage
function insertToLocalStorage(id, value) {
    if (isWebStorageSupported) {
        if (id != "" && value != "") {
            localStorage.setItem(id, value);
            alert("Saved on Local Storage");
        }
    }
}
//check whether the browser supports web storage and
//and insert to session storage
function insertToSessionStorage(id, value) {
    if (isWebStorageSupported) {
        if (id != "" && value != "") {
            sessionStorage.setItem(id, value);
            alert("Saved on Session Storage");
        }
    }
}
Then I am retrieving the items stored in both local storage and session storage. I am going to check the data in web storage in the same browser session and after closing and re opening the browser.
//check whether the browser supports web storage and
//show all items from local storage
function getAllFromLocalStorage() {
   if (isWebStorageSupported) {
       for (var i = 0, len = localStorage.length; i < len; i++) {
           var key = localStorage.key(i);
           var value = localStorage.getItem(key);
           alert(key + "=" + value);
       }
   }
}

//check whether the browser supports web storage and
//show all items from session storage
function getAllFromSessionStorage() {
   if (isWebStorageSupported) {
       for (var i = 0, len = sessionStorage.length; i < len; i++) {
           var key = sessionStorage.key(i);
           var value = sessionStorage.getItem(key);
           alert(key + "=" + value);
       }
   }
}
After checking, I can see that local storage is not becoming empty even after closing and re opening. But session storage is becoming empty, when the browser has been closed.

To clear the local storage and session storage explicitly, you can use the following method.
//clear all items from session and local storage
function clearStorage()
{
    if (isWebStorageSupported) {
        sessionStorage.clear();
        localStorage.clear();
        alert("Local and Session Storage Cleared.")
    }
}
Now I am going to give you a little hint about a place where you can see the items in the local storage and session storage in Google Chrome. In the page, go to Inspect element and then go to Resources tab. There you can find the Local Storage and Session Storage.

Local Storage
Session Storage
I am uploading the full sample to my SkyDrive. Do check it out.



Happy Coding.

Regards,
Jaliya

Wednesday, May 8, 2013

Bing Maps for Silverlight – Get Current Location

I was using Bing Maps in a Silverlight application and I wanted to get current browser location. So I needed to call JavaScript code from the Silverlight .NET code. For that in Silverlight we have System.Windows.Browser namespace, which will provide classes which enables the interaction between managed code and JavaScript in Silverlight-based applications.

I have a Silverlight application and in my MainPage.xaml, I have a Map which I named as “MyMap”. This is the logic of what I am going to do to get the current browser location.
  1. Expose all the managed code objects, which I am going to access from JavaScript  In this case is’s “MyMap” and “Microsoft.Maps.MapControl.Location”.
  2. Find the location coordinates of the browser using JavaScript.
  3. Create a Microsoft.Maps.MapControl.Location object inside JavaScript and fill it’s latitude and longitude properties with the current location coordinates.
  4. Find my Silverlight object in the browser and inside my Silverlight object, find “MyMap” and set it’s location and zoom level.
Now lets see this in action. So before you can invoke any managed code from JavaScript, you first need to register the objects you want to expose to the browser.
HtmlPage.RegisterScriptableObject("MyMap", MyMap);
Since I want to create a Microsoft.Maps.MapControl.Location object inside java script  I am Registering Location as a managed type so it is available for creation from JavaScript code.
HtmlPage.RegisterCreateableType("Location", typeof(Location));
Now I have two JavaScript functions.
function GetUserLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(SetMapPosition);
    }
}
 
function SetMapPosition(position) {
    var location = document.getElementById('MySilverlightObject').Content.services.createObject("Location");
    location.Latitude = position.coords.latitude;
    location.Longitude = position.coords.longitude;
    document.getElementById('MySilverlightObject').Content.MyMap.Center = location;
    document.getElementById('MySilverlightObject').Content.MyMap.ZoomLevel = 10;
}
Here this is what happens.
  1. Check if Geolocation is supported.
  2. If supported, run the getCurrentPosition() method.
  3. If the getCurrentPosition() method is successful, it returns a coordinates object to the function specified in the parameter which is SetMapPosition.
  4. The SetMapPosition() function will get my silverlight object. Inside silverlight object, sets the properties to MyMap object which I have exposed to the browser from the code behind.
This is output. Since I am in Colombo, Sri Lanka, Map is zoomed to Colombo.
Untitled1
Default Map
Untitled2
My Location
I have uploaded a full sample to my SkyDrive.



Happy Coding.

Regards,
Jaliya