UserData Intrinsic IE Persisitence Behavior Client - Side Data Store

By Peter A. Bromberg, Ph.D.

Peter Bromberg  

Earlier this year, I previewed a technique I'd developed for preventing users from navigating away from a page with a partially or even fully filled out form that had not been submitted (Dirty Forms and the User Data Behavior with XMLDocument property). In that article, I showed how to iterate through a form collection, saving each form element's value to a UserData persistence behavior attached to a <SPAN> element on the page, and be able to retrieve all the data and repopulate the form when the user returned. I believe the UserData intrinsic Client-side persistence behavior, which has been available since IE 5.0, is one of the most under-utilized features of the Internet Explorer browser, possibly because the examples provided by Microsoft leave something to be desired.



Now I want to extend the concept to show how the UserData behavior can be accessed on any web page using a standardized set of "generic functions", and this can enable you to build up rich sets of name-value pairs of virtually any type - all on the client - side, and persist the data (up to 64K per page) to the client. Just as you might have a set of generic functions that help you insert, update and retrieve data from your database, you will find that these functions, or variations of them, can make your UserData behavior similarly useful.

As explained in my previous article, UserData and all of its built-in behavior brethren, works like this: We put in a style class declaration in our <HEAD> section:

<STYLE TYPE="text/css"> .userData {behavior:url(#default#userdata);}</STYLE>

Then we ATTACH this behavior through a class attribute to an element on the page. It could be a <DIV>, a <SPAN>, whatever. Here's mine:

<SPAN CLASS="userData" ID="spnUserData"></SPAN>

It is in this <SPAN> tag that we will store our data via the XMLDocument property that the behavior exposes. So first, let's take a look at our generic functions and see how they work, and then I'll give you a link to a client-side page that will let you experiment with them.

I've written five total functions here - you can probably come up with a few more once you've studied the concept. They are:

  • loadUserData - loads the userData object to a data storage element with a specific name, from a userData collection with a specific (previously-saved) name.
  • saveUserData - save current data from the specified page element, to the specified Data Object name, with a specific expiration date in minutes.
  • addUserDataElement - add a data element to the specified data storage element, specifying the name and value for the data element.
  • getUserDataElement - retrieve a data element value by specifying its name, from the specified data storage page tag.
  • removeUserDataElement - remove a specified data element from the specified data storage page tag.

Obviously, you could write a function to retrieve elements by index value, to sort elements, etc., etc.

The key to understanding the behavior is that the XMLDocument property it exposes has one main element- "<ROOTSTUB />" Everything you add to this via the DOM is going to be an attribute of that one element. So for example if you add attribute name "BANKACCOUNT" with value "ZERO", your main element will look like <ROOTSTUB BANKACCOUNT="ZERO"/>. Now, here are the actual functions:

<SCRIPT LANGUAGE="Javascript">

function saveUserData(objStoreElemName , objDataName, iExpiryMin){
var oTimeNow = new Date(); // Start Time
oTimeNow.setMinutes(oTimeNow.getMinutes() + iExpiryMin);
var sExpirationDate = oTimeNow.toUTCString();
objStoreElemName.expires = sExpirationDate;
document.all[objStoreElemName].save(objDataName);
}

function loadUserData(objStoreElemName, objDataName){
document.all[objStoreElemName].load(objDataName);
document.all[objStoreElemName].innerText=objDataName;
}

function addUserDataElement(objStoreElemName, objUElemName, objUElemValue){
document.all[objStoreElemName].setAttribute( objUElemName,objUElemValue);
}

function getUserDataElement (objStoreElemName, objElemName){
var res= document.all[objStoreElemName].getAttribute(objElemName);
return res;
}

function removeUserDataElement(objStoreElemName, objElemName){
document.all[objStoreElemName].removeAttribute(objElemName);
}

</SCRIPT>

That's really all you need to completely manipulate and store gobs of data on the client. The neat thing is that if you have a link to another page, you can load the UserData by name right back into the new page and your visitor can be made to carry it with them all over your site. You can use this for a shopping cart, for user preferences, the contents of a recordset, just about anything you want. Don't forget also that you can store an array of values in a single attribute by using the split and join functions to serialize the array into a string using a delimiter character to separate the values.

All we need now is a page to test out these functions. So instead of boring you with more code, I thought it would be nice to let you bring it up and try it yourself: To get the complete code, just "view source" or save the page locallly.

Think about ways you can use the technique presented here to lessen the load on your server and provide a more professional and meaningful experience to your users. Visit our forums and post your questions or discoveries for others to share.

 

Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer /Analyst at in Orlando and a co-developer of the NullSkull.com developer website. He can be reached at info@eggheadcafe.com