Moving user state to the browser

Thanks to HTML5's Local Storage, it is now much more feasible to move your entire site's user state to the browser client.

User state

What is "user state" anyway? In the case of a typical e-commerce site, this would include the user's shopping cart, and any partially completed forms in the order process. You might also have a customer login status and customer preferences. For Pampered Poultry, I have a cart and an order form.

Since older browsers don't support Local Storage, relying on it for a public web site is not acceptable. So I opted to store the user's cart in browser Cookies, since the cart data is so small and simple. I decided to store any partialy completed forms in Local Storage for users with modern browsers, but fallback to Cookies for users with older browsers.

Testing if Local Storage is supported

It's very easy to test if the user's browser supports Local Storage. For example:

// Determine id local storage is available
if (typeof(Storage) !== 'undefined') {
    localStorageEnabled = true;
} else {
    localStorageEnabled = false;
}

Using Local Storage and Cookies

Local Storage and Cookies both use a key/value approach, so sharing the same functionality across these two technologies can be easy. Cookies are more limited in size and performance- for a starting guide, you shouldn't exceed 50 cookies per domain, or more than 4093 bytes per domain. Local Storage will grant you 5M more of data space!

The key/value approach becomes very powerful when you realize you can use a key such as 'cart' and a value that is a JSON string of all the user's shopping cart data. That means we only need one simple line of code to write or read the whole cart object to/from Local Storage or Cookies!

Note that when you store data in Cookies, that data will be sent back and forth with every server request. This is another reason why Local Storage is such an improvement, as it lives on the browser and is not sent in the HTTP requests.

To read and write Local Storage:

The following code sets the Local Storage key 'USER_CART' to a JSON string representing the current cart object data:

localStorage.setItem('USER_CART', JSON.stringify(cart));

Now you can read this data out of Local Storage and process it back to JavaScript data as follows:

USER_CARTstr = localStorage.getItem('USER_CART');

if (USER_CARTstr) {
    cart = JSON.parse(USER_CARTstr);
} 

To read and write Cookies:

I use the following two JavaScript functions to emulate the Local Storage functions above:

function setCookie(name, value) {
    var cookieStr = name + '=' + value + ';path=/;domain=' + thisSiteDomain;
    document.cookie = cookieStr;
}

function getCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

Note: The setCookie function expects a global thisSiteDomain variable to contain your site's domain, since cookies are stored at the domain level. For site-wide cookies, use '.mydomain.com'. Or you can kee your cookies per-subdomain such as 'orders.mydomain.com'. For localhost, such as when testing on your local laptop, use an empty string ('') for the domain.

JSON concerns

A couple notes about using JSON functions in the browser:

Browser support- Older versions of IE do not support the JSON JavaScript functions. To work around this issue, just download and reference the JSON 3 library. Use the following code in the <head> section of your HTML:

<!--[if lte IE 8]>
<link href="/css/ie.css" rel="stylesheet" />
<script type="text/javascript" src="/js/json3.min.js"></script>
<![endif]-->

JSON.parse- Unless you are 100% certain the string in question is valid JSON, be sure to run the parse function in a try/catch:

try {
    data = JSON.parse(dataStr);
} catch(err) {
    // Handle error here
}

If JSON.parse tries to process invalid JSON, it will crash your application unless you trap the error. I tend not to worry about it for front end variables that have only been created using a JSON.stringify() command. But I do use it on anything sent to/from the server via Ajax, etc.

Next post I will talk about Content-forward design.

For a full introduction and index to this blog: Node.js: One New Approach

Cheers!

comments powered by Disqus