Monthly Archives: April 2011

HTML5 Local Storage

There is a feature in HTML5 that enables you to store named key/value pairs in the local storage of your browser.  The advantage over using regular cookies is that your data is never send to the remote web server and that you can store a lot more compared to the 4KB limitation of cookie storage space.

As the local storage is a feature making part of the HTML5 specification, only modern browser supports is;
Safari 4.0, Opera 10.5,IE8, FireFox 3.5, Chrome 4.0 and IOS above version 2.0.

As for any feature of HTML5 before using it you should check if your browser supports the feature:

   1: function can_use_html5() {

   2:    try {

   3:        return 'localStorage' in window && window['localStorage'] !== null;

   4:    } 

   5:    catch (e) {

   6:        return false;

   7:    }

   8: }

To store or retrieve an item from the local storage:

   1: //Retireve an item:

   2: var item = localStorage.getItem("mykey");

   3: //Store an item:

   4: localStorage.setItem("myKey", "myValue");

To clear an item from the local storage or remove all items:

   1: //Remove an item

   2: localStorage.removeItem("myKey");

   3: //Remove all

   4: localStorage.clear();

 

With this feature we are now able to build web applications that can work offline.  Here under I build an application that stores persons profiles in the local storage.  I use the JSON.stringify method to serialize the persons before storing the JSON strings in the local storage and JQuery to retrieve the values and bind the events:

   1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

   2: <html xmlns="http://www.w3.org/1999/xhtml">

   3: <head>

   4:     <title>Local Storage</title>

   5:     <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.1.js" type="text/javascript"></script>

   6: </head>

   7:  

   8: <body>

   9:     <div id="resultMessage">&nbsp;</div>

  10:     <table style="position: absolute; left: 10px;">  

  11:         <tr>

  12:             <td>

  13:             Firstname:

  14:             </td>

  15:             <td><input type="text" id="firstname" />

  16:             </td>

  17:         </tr>

  18:         <tr>

  19:             <td>

  20:             Lastname:

  21:             </td>

  22:             <td><input type="text" id="lastname" />

  23:             </td>

  24:         </tr>

  25:         <tr>

  26:             <td>

  27:             E-mail: 

  28:             </td>

  29:             <td><input type="text" id="email" />

  30:             </td>

  31:         </tr>

  32:          <tr>

  33:             <td>

  34:                 <input type="button" id="save"  value="Create" />

  35:             </td>

  36:             <td>

  37:                 <input type="button" id="print"  value="Print"/>

  38:             </td>

  39:         </tr>

  40:     </table>

  41:     <script type="text/javascript">

  42:         $(function () {

  43:             if (!can_use_html5()) {

  44:                 alert("This browser does not support Html5 storage, upgrade or change your browser!");

  45:             }

  46:         });

  47:  

  48:         $(function () {

  49:             $("#save").click(function () {

  50:                 

  51:                 var person = getPerson();

  52:                 

  53:                 //simple validation

  54:                 if (person == null) {

  55:                     alert("Fill in all fields please!");

  56:                     return;

  57:                 }

  58:                 

  59:                 var jsData = JSON.stringify(person);

  60:                 localStorage.setItem($("#email").val(), jsData);

  61:                 

  62:                 $("#resultMessage").html($("#email").val() + " stored in local storage");

  63:                 clearAllText();

  64:             })

  65:         });

  66:  

  67:         $(function () {

  68:             $("#print").click(function () {

  69:                 for (var i = 0; i < window.localStorage.length; i++) {

  70:                     document.write('<div id="record_' + i + '"> ' + localStorage[localStorage.key(i)] + '</div>');

  71:                 }

  72:                 localStorage.clear();

  73:             })

  74:         });

  75:  

  76:         function getPerson() {

  77:             var firstname = $("#firstname").val();

  78:             var lastname = $("#lastname").val();

  79:             var email = $("#email").val();

  80:             //simple validation

  81:             return (firstname == "" || lastname == "" || email == "") ? null : { Firstname: firstname, Lastname: lastname, Email: email };

  82:         }

  83:  

  84:         function can_use_html5() {

  85:             try {

  86:                 return 'localStorage' in window && window['localStorage'] !== null;

  87:             } 

  88:             catch (e) {

  89:                 return false;

  90:             }

  91:         }

  92:  

  93:         function clearAllText() {

  94:             

  95:             $("#firstname").attr("value", "");

  96:             $("#lastname").attr("value", "");

  97:             $("#email").attr("value", "");

  98:         }

  99:     </Script>

 100: </body>

 101: </html>

HTML5 enables new possibilities for all types of scenarios like creating IPAD/IPhone web applications without having to program in objective c and/or upload the app to the app store.  In a future post I will demonstrate how you can extend this application to create such an application.   

kick it on DotNetKicks.com

Answer for Puzzle 2

public IEnumerator GetEnumerator()

{

for (int index = 0; index < values.Length; index++)

{

yield return values[(index + startingPoint) % values.Length];

}

}

This small code block of c#2 replaces the entire Iterator class. The trick here is in the yield return statement.  When you write this statement you actually ask .Net to create a state machine for you. This statement is keeping track of what we were doing when we last returned a value.  Every time the yield return statement is hit the method returns but when the calling method ask for the next element in the IEnumerable collection you re-enter the method just after the last yield return statement as you would never have left it. All the state of the local variables inside the IEnumerator method is preserved.  What is also important to understand is that trick is not performed by the runtime but by the compiler so you don’t incurs real performance lost.

Puzzle 2: iterators using the yield statement (intermediate)

Remove the iterator class from the listing and replace the call to the iterator class, inside the iteration sample(line 29), by using the yield operator of C#2.

The output of the Problem() method should remain the same.

  1: using System;
  2: using System.Collections;
  3: 
  4: namespace Puzzles
  5: {
  6: 
  7:     public class Enumarators
  8:     {
  9:         public static void Problem()
 10:         {
 11:             var myValues = new[] { "a", "b", "c", "d" };
 12:             var col = new IterationSample(myValues);
 13:             foreach (var x in col)
 14:             {
 15:                 Console.WriteLine(x);
 16:             }
 17:         }
 18: 
 19:         public class IterationSample : IEnumerable
 20:         {
 21:             internal object[] values;
 22: 
 23:             public IterationSample(object[] values)
 24:             {
 25:                 this.values = values;
 26:             }
 27:             public IEnumerator GetEnumerator()
 28:             {
 29:                 return new Iterator(this);  //Change this line by using yield
 30:             }
 31:         }
 32: 
 33:         public class Iterator:IEnumerator
 34:         {
 35:             IterationSample parent;
 36:             int position;
 37: 
 38:             internal Iterator(IterationSample parent)
 39:             {
 40:                 this.parent = parent;
 41:                 position = -1;
 42:             }
 43:             public bool MoveNext()
 44:             {
 45:                 if (position != parent.values.Length)
 46:                 {
 47:                 position++;
 48:                 }
 49:                 return position < parent.values.Length;
 50:             }
 51:             public object Current
 52:             {
 53:                 get
 54:                 {
 55:                     if (position==-1 || position==parent.values.Length)
 56:                     {
 57:                      throw new InvalidOperationException();
 58:                     }
 59:                     return parent.values[position];
 60:                 }
 61:             }
 62:             public void Reset()
 63:             {
 64:                 position = -1;
 65:             }
 66:         }
 67:     }
 68: }
 69: 

Answer for puzzle 1

The result is: xhello

The thing here is that because the stringbuilder is a reference type, when you change the content of the stringbuilder inside the method AppendHello() this change is reflected in the caller method –> Problem() but when you set the stringbuilder to null this change is not visible inside the caller method.

This is because in .Net all parameters are passed by value, even reference types. For reference types it’s not the value of the object itself that is passed by value but a pointer to the underlying value (the reference). The pointer is copied on the stack and is passed by value. When you change the value inside the called method this change is reflected in the underlying value and is visible for the calling method. When you set the pointer to null inside the called method you only destroy the copied pointer not the underlying value.