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
|