Sunday, May 20, 2012

HTML5 WEB SQL = Amazing Concept

The Web SQL database API isn’t actually part of the HTML5 specification, but it is part of the suite of specifications that allows us developers to build fully fledged web applications.
  1. It is just like it says on the tin: an offline SQL database. Implementations today are based on SQLite, a general-purpose open-source SQL engine. It comes with all the pros and cons of traditional databases.
  2. On the one hand, you have a fully relational structure, allowing you to rapidly query and manipulate data via joins, e.g. "delete all saved game where the level is less than 10 and the game hasn't been loaded in the past 30 days". You can express that in a line of SQL, whereas you'd have to manually wander through the equivalent corpus of Web Storage data. And if you have a strong need for performance, you can also lean on several decades of research on database optimisation (though tuning would have to be done separately for each possible SQL engine being used).
  3. Furthermore, there's support for transactions, your database is protected from the kind of race conditions that can arise with Web Storage.

There are three core methods in the spec that I’m going to cover in this article:
  1. openDatabase
  2. transaction
  3. executeSql
Support is a little patchy at the moment. Only Webkit (Safari, SafariMobile and Chrome) and Opera support web databases.

Creating and opening databases

If you try to open a database that doesn’t exist, the API will create it on the fly for you. You also don’t have to worry about closing databases.
To create and open a database, use the following code:
var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);

We have passed four arguments to the openDatabase method. These are:
  1. Database name
  2. Version number
  3. Text description
  4. Estimated size of database

transaction
Now that we’ve opened our database, we can create transactions. Transactions give us the ability to rollback. This means that if a transaction — which could contain one or more SQL statements — fails (either the SQL or the code in the transaction), the updates to the database are never committed — i.e. it’s as if the transaction never happened.
There are also error and success callbacks on the transaction, so you can manage errors, but it’s important to understand that transactions have the ability to rollback changes.
The transaction is simply a function that contains some code:

var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);
db.transaction(function (tx) {
  // here be the transaction
  // do SQL magic here using the tx object
});

executeSql
executeSql is used for both read and write statements, includes SQL injection projection, and provides a callback method to process the results of any queries you may have written.
Once we have a transaction object, we can call executeSql:

var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE foo (id unique, text)');
});

This will now create a simple table called “foo” in our database called “mydb”. Note that if the database already exists the transaction will fail, so any successive SQL wouldn’t run. So we can either use another transaction, or we can only create the table if it doesn’t exist, which I’ll do now so I can insert a new row in the same transaction:



var db = openDatabase('mydb', '1.0', 'my first database', 2 *1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS foo (id unique, text)');
tx.executeSql('INSERT INTO foo (id, text) VALUES (1, "synergies")');
});

Now our table has a single row inside it. What if we want to capture the text from the user or some external source? We’d want to ensure it can’t compromise the security of our database (using something nasty like SQL injection). The second argument to executeSql maps field data to the query, like so:
tx.executeSql('INSERT INTO foo (id, text) VALUES (?, ?)', [id,userValue]);
id and userValue are external variables, and executeSql maps each item in the array argument to the “?”s.

Finally, if we want to select values from the table, we use a callback to capture the results:

tx.executeSql('SELECT * FROM foo', [], function (tx, results){
  var len = results.rows.length, i;
for (i = 0; i < len; i++) {
alert(results.rows.item(i).text);
}
});

(Notice that in this query, there are no fields being mapped, but in order to use the third argument, I need to pass in an empty array for the second argument.)

The callback receives the transaction object (again) and the results object. The results object contains a rows object, which is array-like but isn’t an array. It has a length, but to get to the individual rows, you need to use results.rows.item(i), where i is the index of the row. This will return an object representation of the row. For example, if your database has a name and an age field, the row will contain a name and an age property. The value of the age field could be accessed using results.rows.item(i).age.

Sample example to demonstrate the usage of WEB SQL api’s is as follows:

<html>
<head>
<script type="text/javascript">
var db;
try{
db=openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
}catch(err){
document.write("Your browser does not support WEB SQL");
}
function checkBrowser(){
if(!db){
document.getElementById('content').innerHTML="";
}
}
function insertToDb(){
var id=document.getElementById("id").value;
var message=document.getElementById("message").value;
db.transaction(function(tx){
var table=document.getElementById("table").value;
tx.executeSql('INSERT INTO '+table+' (id,message) VALUES (?, ?)',[id,message]);
});
displayDbContents();
}
function deleteRow(id){
db.transaction(function(tx){
var table=document.getElementById('table').value;
tx.executeSql('DELETE FROM '+table+' WHERE id=?',[id]);
displayDbContents();
});
}
function displayDbContents(){
db.transaction(function(tx){
var table=document.getElementById("table").value;
tx.executeSql('SELECT * FROM '+table,[],function(tx,results){
var i,len=results.rows.length;
var buffer="<table border='1px'><tr><th>ID</th><th>MESSAGE</th><th>DELETE</th></tr>";
for(i=0;i<len;i++){
buffer=buffer+"<tr><td>"+results.rows.item(i).id+"</td><td>"+results.rows.item(i).message+"</td><td><input id="+results.rows.item(i).id+" type='button' value='Delete' onclick='deleteRow(this.id)'/></td></tr>";
}
buffer=buffer+"</table>";
document.getElementById('result').innerHTML=buffer;
});
});
}
function createTable(){
document.getElementById('table').disabled=true;
document.getElementById('createid').disabled=true;
db.transaction(function (tx) {
var table=document.getElementById('table').value;
tx.executeSql('CREATE TABLE IF NOT EXISTS '+table+' (id unique, message)');
alert("Table created with 2 columns(id, message)");
document.getElementById('id').disabled=false;
document.getElementById('message').disabled=false;
document.getElementById('submit').disabled=false;
displayDbContents();
document.getElementById('drop').disabled=false;
});
}
function dropTable(){
db.transaction(function(tx){
var table=document.getElementById('table').value;
tx.executeSql('DROP TABLE '+table,[]);
clearAll();
document.getElementById('result').innerHTML="";
});
}
function clearAll(){
document.getElementById('table').disabled=false;
document.getElementById('table').value="";
document.getElementById('createid').disabled=false;
document.getElementById('id').disabled=true;
document.getElementById('id').value="";
document.getElementById('message').disabled=true;
document.getElementById('message').value="";
document.getElementById('submit').disabled=true;
}
</script>
</head>
<body onload="checkBrowser()">
<div id="content">
<table width="100%" border="1px">
<tr><td align="center">Create and Insert data</td><td align="center">Table Contents</td></tr>
<tr>
<td width="50%" align="center">
<table>
<tr><td>Create Table</td><td><input type="text" id="table" placeholder="Enter Table Name"/><input type="button" id="createid" value="Create Table" onclick="createTable()"/></td></tr>
<tr><td>ID</td><td><input type="text" id="id" placeholder="Enter ID" disabled/></td></tr>
<tr><td>Message</td><td><input type="text" id="message" placeholder="Enter Message" disabled/></td></tr>
<tr><td><input type="button" value="Submit" id="submit" onclick="insertToDb()" disabled/></td><td></td></tr>
</table>
</td>
<td width="50%" align="center">
<div id="result">
</div>
<input type="button" value="Drop table" onclick="dropTable()" id="drop" disabled/>
</td>
</tr>
</table>
</div>
</body>
</html>


Observations on different browsers:

Internet Explorer


Mozilla Firefox


Opera



Safari



Google Chrome



Browser compatibilities

From the observation made in the test applications, the conclusions are as follows.
Browser
WEB SQL support
Internet ExplorerNo
Mozilla FirefoxNo
OperaYes
SafariYes
Google ChromeYes

Wednesday, May 16, 2012

HTML5 Web Storage

What is HTML5 Web Storage?

With HTML5, web pages can store data locally within the user's browser. Earlier, this was done with cookies. However, Web Storage is more secure and faster. The data is not included with every server request, but used ONLY when asked for. It is also possible to store large amounts of data, without affecting the website's performance. The data is stored in key/value pairs, and a web page can only access data stored by itself.

localStorage and sessionStorage

There are two new objects for storing data on the client:

  • localStorage - stores data with no expiration date
  • sessionStorage - stores data for one session
Before using web storage, check browser support for localStorage and sessionStorage:

if(typeof(Storage)!=="undefined")
 {
  // Yes! localStorage and sessionStorage support!
// Some code.....
 }
else
 {
  // Sorry! No web storage support..
 }

The localStorage Object

The localStorage object stores the data with no expiration date. The data will not be deleted when the browser is closed, and will be available the next day, week, or year.

The sessionStorage Object

The sessionStorage object is equal to the localStorage object, except that it stores the data for only one session. The data is deleted when the user closes the browser window.

Where to Use Web Storage?

Some examples of implementation scenarios include storing the data for an online to-do list (then pushing to the server in intervals instead of in real-time) or saving products that the user places in his shopping cart. The data can be made available between page requests, multiple browser tabs, and also between browser sessions using localStorage.

Your apps can actually be used offline completely using localStorage. Data can then be sent and stored server-side when the user is online again.
From another perspective, Web Storage can be a great performance win when some static data is stored on the client to minimize the number of subsequent requests. Even images can be stored in strings using Base64 encoding.

For the examples mentioned above, it makes sense to use localStorage. You may be wondering, then, when you should opt for sessionStorage.

In some cases, you simply want to get rid of the data as soon as the window is closed. Or, perhaps, you don’t want the application to interfere with the same application that’s open in another window (e.g. when running two instances of a Scrabble game or running multiple unit tests simultaneously, you don’t want data to collide). These scenarios are served best with sessionStorage.

HTML5 Web Storage Methods
  • setItem(key,value): adds a key/value pair to the sessionStorage object.
  • getItem(key): retrieves the value for a given key.
  • clear(): removes all key/value pairs for the sessionStorage object.
  • removeItem(key): removes a key/value pair from the sessionStorage object.
  • key(n):retrieves the value for key[n].

Setting a Key/Value
There are two different methods for setting information into sessionStorage & localStorage:
sessionStorage.setItem('someKey','someValue');
localStorage.setItem('someKey','someValue');
...or you could just use the shortcut method:
sessionStorage.someKey = 'someValue';
localStorage.someKey = 'someValue';

Getting a Value
There are two methods to retrieve a key/value pair as well:
sessionStorage.getItem('someKey'); //returns 'someValue'
localStorage.getItem('someKey');
...or simply reference the sessionStorage object:
sessionStorage.someKey; //returns 'someValue'
localStorage.someKey;

Removing a Key/Value
sessionStorage.removeItem('someKey');
localStorage.removeItem('someKey');
All you need to do is provide the key to the removeItem method.

Clearing Storage
sessionStorage.clear(); //everything gone
localStorage.clear();
A simple clear call -- that's it.

EXAMPLE

This is an example to demonstrate the usage of localStorage and sessionStorage objects accross different browsers.

//webstorage.html
<html>
<head>
<script type="text/javascript">
function loadPrev(){
if(typeof(Storage)!="undefined"){
try{
if(localStorage.getItem('name')){
var tag="<table border='1px'><tr><th>Name</th><th>Age</th><th>Sex</th></tr>";
tag=tag+"<tr><td>"+localStorage.getItem('name')+"</td><td>"+localStorage.getItem('age')+
"</td><td>"+localStorage.getItem('sex')+"</td></tr></table>"
document.getElementById('localStorage').innerHTML=tag;
}
else
document.getElementById('localStorage').innerHTML="Nothing to display";
}
catch(err){
document.getElementById('localStorage').innerHTML="Your browser does not support this feature";
}
try{
if(sessionStorage.getItem('name')){
var tag="<table border='1px'><tr><th>Name</th><th>Age</th><th>Sex</th></tr>";
tag=tag+"<tr><td>"+sessionStorage.getItem('name')+"</td><td>"+sessionStorage.getItem('age')+"</td><td>"+sessionStorage.getItem('sex')+"</td></tr></table>"
document.getElementById('sessionStorage').innerHTML=tag;
}
else
document.getElementById('sessionStorage').innerHTML="Nothing to display";
}
catch(err){
document.getElementById('sessionStorage').innerHTML="Your browser does not support this feature";
}
}
else{
document.getElementById('localStorage').innerHTML="Your browser does not support this feature";
document.getElementById('sessionStorage').innerHTML="Your browser does not support this feature";
}
}
function webstore(){
if(typeof(Storage)!="undefined"){
var name=document.getElementById('name').value;
var age=document.getElementById('age').value;
var sex=document.getElementById('sex').value;
var storage=document.getElementById('storage').value;
if(storage=="localStorage"){
localStorage.setItem('name',name);
localStorage.setItem('age',age);
localStorage.setItem('sex',sex);
}
else if(storage=="sessionStorage"){
sessionStorage.setItem('name',name);
sessionStorage.setItem('age',age);
sessionStorage.setItem('sex',sex);
}
loadPrev();
}
}
function clearStorage(){
var res=confirm("Are you sure about clearing the localStorage and sessionStorage data?");
if(res){
try{
localStorage.clear();
sessionStorage.clear();
loadPrev();
}catch(err){
loadPrev();
}
}
}
</script>
</head>
<body onload="loadPrev()">
<table width="100%"  border="1px">
<tr><th>Form</th><th>Local Storage</th><th>Session Storage</th></tr>
<tr>
<td style="width :40%" align="center">
<span>
<table>
<tr><td>Name</td><td><input type="text" id="name" placeholder="Enter Name"/></td></tr>
<tr><td>Age</td><td><input type="text" id="age" placeholder="Enter Age"/></td></tr>
<tr>
<td>Sex</td>
<td>
<select id="sex" style="width :100%">
<option>Male</option>
<option>Female</option>
</select>
</td>
</tr>
<tr>
<td>Storage Type</td>
<td>
<select id="storage" style="width :100%">
<option>localStorage</option>
<option>sessionStorage</option>
</select>
</td>
</tr>
<tr><td><input type="button" value="Store Value" onclick="webstore()"/></td><td><input type="button" value="Clear Storage" onclick="clearStorage()"/></td></tr>
</table>
</span>
</td>
<td style="width :30%" align="center">
<span id="localStorage">
</span>
</td>
<td style="width :30%" align="center">
<span id="sessionStorage">
</span>
</td>
</body>
</html>

Test across different browsers

Internet Explorer



Mozilla Firefox



Opera





Safari



Google Chrome





Browser compatibilities:
From the observations made from the test application the conclusions are as follows
Browser
localStorage
sessionStorage
Internet ExplorerNoNo
Mozilla FirefoxYesNo
OperaYesYes
Apple SafariYesYes
Google chromeYesYes