Home Articles FAQs XREF Games Software Instant Books BBS About FOLDOC RFCs Feedback Sitemap
irt.Org

Related items

Intelligent Cookies

Chocolate Chip Cookies + Automating NEW!

Form -> Cookie -> Form

You are here: irt.org | Articles | JavaScript | Cookie | Form -> Cookie -> Form [ previous next ]

Published on: Sunday 15th June 1997 By: Martin Webb

Introduction

The code described here is generic, i.e. it can be used with any type of form you wish to produce.

It supports the storing of information from the following form element types:

Form Elements

It is important to distinguish the type of element when setting its value, as its type dictates how the value is set.

To set the value of a text element, the following syntax is used:

document.formName.elementName.value = elementValue;

To set a select element, the following syntax is used:

document.formName.elementName.selectedIndex = elementValue;

To set a radio element, the following syntax is used:

document.formName.elementName[elementValue].checked = true;

To set a checkbox element, the following syntax is used:

document.formName.elementName.checked = true;

One limitation that has to be observed when using a group of radio elements, as the group of radio elements all have the same name (that's why they are a group), the only way the individual radio elements within the group can be accessed is via their index, which must be a numeric integer. Therefore the elementValue used in the above syntax must be a numeric integer that corresponds to the required radio elements index. More about this later.

Rather than create a whole stack of JavaScript functions to vet the element values, and pack them together in preparation to store them as a cookie - we will cheat!

The Search String

One feature of forms, is that when the form is submitted it will pass the value of all its forms elements as a string. This string is passed as the search property of the location object. This nicely bundles up all the names of the elements with their values, which is then passed to the next document.

Within the next document, we can strip the search property and store it whole as the value of new cookie.

Instead of loading a new document, if no new target is specified in the form, it will pass the form string to the current document.

When passing values of checkboxes, when a checkbox is ticked the value "on" is passed, when the checkbox is not ticked no value, and indeed no reference to the checkbox is passed. Therefore one must be careful when marking checkboxes as "checked", because this may override the intention of the user.

Psuedo Code

This then gives up the basis for the code, which can be described by the following psuedo code:

  1. create store variable

  2. If search property contains info:

    1. store search property as cookie

    2. copy search property to store variable

  3. Attempt to get cookie info

  4. If cookie exists:

    1. copy cookie to store variable

  5. Display form using HTML

  6. When page loaded (using onLoad=""):

    1. Interrogate store variable - and update form

  7. If submit button pressed - pass form values back to same document

This then gives us several distinct types of entry to the document:

Escaped Characters

One final point to raise - when form field value which contains spaces is passed as a search string, the spaces are converted by the browser to '+' characters. This is a feature of the browser that converts all non alphanumeric characters to escape characters. For example:

Martin Webb !"£$%^&*()_+

is converted to:

Martin+Webb+%21%22%A3%24%25%5E%26*%28%29_%2B

The spaces are convert to '+' characters and the '+' characters are converted to '%2B'. This is so that search engines can tell which individual words were entered in a search field.

This is not usually a problem as we can convert the string back to its original using the unescape() method, which is this example will convert it back to:

Martin+Webb+!"£$%^&*()_+

Which as you can see hasn't reverted back to the original value. What is required is a simple find and replace function that finds all instances of the '+' character and replaces it with a space character before it is passed to the unescape() method.

Working Example

Right, now that we have got all the "ifs", "buts" and assumptions out of the way, we can now produce some code.

As there has been too much waffle so far why not try out this example which will show the end result. The example is a self contained document, with all HTML and JavaScript functions. All that is required is an understanding of how to adapt it for your own needs.

The JavaScript Source Code

The source code for the above example is show below. It is broken up into pieces to enable us to understand what is going on:

<HTML>

<HEAD>
<LINK REL=STYLESHEET HREF="../../utility/main.css" TYPE="text/css">

The above line refers out to a Cascading Style Sheet - currently supported in Internet Explorer 3+ and Netscape Navigator 4+. Can be removed if not required, or you could copy and adapt it for your own purposes.

<SCRIPT LANGUAGE="JavaScript"><!--
function Get_Cookie(name) {
    var start = document.cookie.indexOf(name+"=");
    var len = start+name.length+1;
    if ((!start) && (name != document.cookie.substring(0,name.length))) return null;
    if (start == -1) return null;
    var end = document.cookie.indexOf(";",len);
    if (end == -1) end = document.cookie.length;
    return unescape(document.cookie.substring(len,end));
}

function Set_Cookie(name,value,expires,path,domain,secure) {
    document.cookie = name + "=" +escape(value) +
        ( (expires) ? ";expires=" + expires.toGMTString() : "") +
        ( (path) ? ";path=" + path : "") + 
        ( (domain) ? ";domain=" + domain : "") +
        ( (secure) ? ";secure" : "");
}

The two cookie functions Get_Cookie() and Set_Cookie() as described in Chocolate Chip Cookies article.

function setupForm() {
    if (userProfile) getValues(userProfile);
}

The setupForm() function is invoked by the onLoad="" event within the <BODY> tag, see further below.

This checks to see if userProfile has been created (i.e. the store variable, as described in the psuedo code), and if it has repopulates the form by invoking the getValues() function by passing the contents of the userProfile.

function getValues(string) {
    getValue(string,"user",   document.profileForm.user,   "text");
    getValue(string,"email",  document.profileForm.email,  "text");    
    getValue(string,"country",document.profileForm.country,"select");    
    getValue(string,"age",    document.profileForm.age,    "select");
    getValue(string,"sex",    document.profileForm.sex,    "radio");

    for (var i=0;i<7+1;i++)
        getValue(string,"i"+i, eval("document.profileForm.i"+i), "checkbox");
}

The getValues() function is the one place where you may need to adapt the contents to populate your form.

The current contents sets the form profileForm elements user, email, country, age, sex and i0 through to i7.

The getValues() function is passed the parameter string which holds the contents of the userProfile. This is then used by each call to getValue along with the name of the form element, a reference to the element (which includes the name of the form and the name of the form element) and the type of the element, i.e. text, select, radio, or checkbox

The last two lines of the getValues() function show a simple means of looping through a list of like named form elements, by just changing the i suffix each time. It requires the use of the eval() method to convert a string into the actual reference of the element.

To adapt this function for your own form, requires you to add a call to the getValue() function for each of your forms elements, changing the name of the element, the name of the form, and the element type.

function replace(string,text,by) {
// Replaces text with by in string
    var i = string.indexOf(text);
    var newstr = '';
    if ((!i) || (i == -1)) return string;
    newstr += string.substring(0,i) + by;

    if (i+text.length < string.length)
        newstr += replace(string.substring(i+text.length,string.length),text,by);
    
    return newstr;
}

The replace() function simply replaces any occurences of the text string within the string string with the by string.

function onCheck(string) { if (string == "on") return true; return false; }

The onCheck() function is used by the following getValue() function to return true if passed "on".

function getValue(string,elementName,object,elementType) {
// gets value of elementName from string and populates object of elementType

    var startPos = string.indexOf(elementName + "=")
    
    if (startPos > -1) {
        startPos = startPos + elementName.length + 1;
        var endPos = string.indexOf("&",startPos);
        if (endPos == -1) endPos = string.length;

        var elementValue = unescape(string.substring(startPos,endPos));
        
        if (elementType == "text")     object.value = elementValue;
        if (elementType == "password") object.value = elementValue;
        if (elementType == "select")   object.selectedIndex = elementValue;
        if (elementType == "checkbox") object.checked = onCheck(elementValue);
        if (elementType == "radio")    object[elementValue].checked = true;
    }
}

The getValue() function is the guts of the whole code. It attempts to find the elementName, within the passed string (i.e. the store variable as described in the psuedo code). It does so by searching for the name of the element plus the "=" character using the indexOf() method.

If it is not found it simply returns to the invoking getValues() function.

If it is found then it searchs for the "&" character, which is used to append the form name value pairs together, again using the indexOf() method.

If the "&" character is not found then it is assumed to be the last form name value pair within the string.

The elementValue of the element is then extracted using the substring() and unescape() methods.

Then based on the elementType passed to getValue it sets the value of the object (i.e. reference to element) as required.

Where the elementType is a "checkbox" it uses the onCheck() function to set the value of the checked property to true, it eh elementValue is "on".

Where the elementType is a "radio" the assumption is that the name of the radio element is the same as its index number.

//--></SCRIPT>

</HEAD>

All the JavaScript functions are placed within the HTML <HEAD> and </HEAD> tags. This ensures they are all loaded by the browser before they are invoked.

The following line of code, includes the onLoad="" event which invokes the setupForm() function when the whole page has been fully loaded.

<BODY onLoad="setupForm()">

<SCRIPT LANGUAGE="JavaScript"><!--
var today = new Date();
var expires = new Date(today.getTime() + (56 * 86400000));

var searchString = replace(self.location.search.substring(1),"+"," ");
if (searchString.length > 0) Set_Cookie("userProfile",searchString,expires);
var userProfile = Get_Cookie("userProfile");

if (!userProfile) {
    document.write('<P>Welcome,<P>According to your records ');
    document.write('you have not set your user profile:');
}
else {
    document.write('<P>Welcome back,<P>According to your records ');
    document.write('the following settings are held in your profile:');
}
//--></SCRIPT>

Finally, some inline JavaScript which is invoked as the page is being laid out. First two dates are created today and expires which is based on today plus 56 days, or 8 weeks.

The search property of the current location, i.e. self.location.search is stripped of its initial "?" using the substring() method, and passed to the replace() function to replace all "+" characters with a space character. And is eventually stored in the searchString variable.

If the length of the searchString is greater than 0 then a cookie called "userProfile" is stored with the value of the searchString and with the expiry date expires using the Set_Cookie() function.

Following this an attempt is made to acquire the value of the "userProfile" using the Get_Cookie() function.

If the cookie is not retrieved then the value of null is returned to the userProfile variable.

This is then tested using !userProfile so that an appropriate message is written to the document.

The remainder of the document is made up of the required form.

Note, to enable us to easily access the option and radio arrays, the value of the options and radio buttons are always set to elements index number.

<FORM NAME="profileForm">
<TABLE width=595 BGCOLOR="#AAAAFF" BORDER=0
CELLSPACING=0 CELLPADDING=5><TR><TD>


<P>Name:
<BR><INPUT TYPE="TEXT" NAME="user" VALUE="" SIZE=40>


<P>Email Address:
<BR><INPUT TYPE="TEXT" NAME="email" VALUE="" SIZE=40>


<P><TABLE WIDTH=100%><TR>
<TD VALIGN=TOP WIDTH=50%>

<P>Country:
<BR><SELECT NAME="country">
<OPTION  VALUE="0">Argentina
<OPTION  VALUE="1">Australia
<OPTION  VALUE="2">Austria
<OPTION  VALUE="3">Belgium
<OPTION  VALUE="4">Bermuda
<OPTION  VALUE="5">Bolivia
<OPTION  VALUE="6">Brazil
<OPTION  VALUE="7">Brunei Darussalam
<OPTION  VALUE="8">Canada
<OPTION  VALUE="9">Caribbean
<OPTION VALUE="10">Chile
<OPTION VALUE="11">China
<OPTION VALUE="12">Colombia
<OPTION VALUE="13">Croatia
<OPTION VALUE="14">Czech Republic
<OPTION VALUE="15">Denmark
<OPTION VALUE="16">Estonia
<OPTION VALUE="17">Europe
<OPTION VALUE="18">Finland
<OPTION VALUE="19">Former USSR
<OPTION VALUE="20">France
<OPTION VALUE="21">Germany
<OPTION VALUE="22">Greece
<OPTION VALUE="23">Hong Kong
<OPTION VALUE="24">Hungary
<OPTION VALUE="25">Iceland
<OPTION VALUE="26">India
<OPTION VALUE="27">Indonesia
<OPTION VALUE="28">Ireland
<OPTION VALUE="29">Israel
<OPTION VALUE="30">Italy
<OPTION VALUE="31">Japan
<OPTION VALUE="32">Korea
<OPTION VALUE="33">Latin America
<OPTION VALUE="34">Luxemburg
<OPTION VALUE="35">Macedonia
<OPTION VALUE="36">Malaysia
<OPTION VALUE="37">Mexico
<OPTION VALUE="38">Middle East
<OPTION VALUE="39">Netherlands
<OPTION VALUE="40">New Zealand
<OPTION VALUE="41">North Africa
<OPTION VALUE="42">Norway
<OPTION VALUE="43">Peru
<OPTION VALUE="44">Philippines
<OPTION VALUE="45">Poland
<OPTION VALUE="46">Portugal
<OPTION VALUE="47">Russia
<OPTION VALUE="48">Russian Federation
<OPTION VALUE="49">Singapore
<OPTION VALUE="50">Slovak Republic
<OPTION VALUE="51">Slovakia
<OPTION VALUE="52">Slovenia
<OPTION VALUE="53">Slovenija
<OPTION VALUE="54">South Africa
<OPTION VALUE="55">South Korea
<OPTION VALUE="56">Spain
<OPTION VALUE="57">Sweden
<OPTION VALUE="58">Switzerland
<OPTION VALUE="59">Taiwan
<OPTION VALUE="60">Thailand
<OPTION VALUE="61">Turkey
<OPTION VALUE="62">United Kingdom
<OPTION VALUE="63" SELECTED>United States
<OPTION VALUE="64">Uruguay
<OPTION VALUE="65">Venezuela
<OPTION VALUE="66">Yugoslavia
</SELECT>

</TD><TD VALIGN=TOP WIDTH=25%>

<P>Age:
<BR><SELECT NAME="age">
<OPTION VALUE="0"> < 10
<OPTION VALUE="1"> 10 - 15
<OPTION VALUE="2"> 16 - 19
<OPTION VALUE="3" SELECTED>  20 - 29
<OPTION VALUE="4"> 30 - 39
<OPTION VALUE="5"> 40 - 49
<OPTION VALUE="6"> 50 - 59
<OPTION VALUE="7"> 60 - 69
<OPTION VALUE="8"> 70+
</SELECT>

</TD><TD VALIGN=TOP WIDTH=25%>

<P>Sex:
<BR><INPUT TYPE="RADIO" NAME="sex" VALUE="0" CHECKED> Male
<BR><INPUT TYPE="RADIO" NAME="sex" VALUE="1"> Female

</TD></TR></TABLE>

<HR>


<TABLE WIDTH=100%>
<TR><TD WIDTH=10%><P>Interests:</TD>
<TD ALIGN=RIGHT WIDTH=45%><P>JavaScript: <INPUT TYPE="CHECKBOX" NAME="i0"></TD>
<TD ALIGN=RIGHT WIDTH=45%><P>Java: <INPUT TYPE="CHECKBOX" NAME="i1"></TD></TR>

<TR><TD WIDTH=10%>&nbsp;</TD>
<TD ALIGN=RIGHT WIDTH=45%><P>JScript: <INPUT TYPE="CHECKBOX" NAME="i2"></TD>
<TD ALIGN=RIGHT WIDTH=45%><P>VBScript: <INPUT TYPE="CHECKBOX" NAME="i3"></TD></TR>

<TR><TD WIDTH=10%>&nbsp;</TD>
<TD ALIGN=RIGHT WIDTH=45%><P>ActiveX: <INPUT TYPE="CHECKBOX" NAME="i4"></TD>
<TD ALIGN=RIGHT WIDTH=45%><P>HTML: <INPUT TYPE="CHECKBOX" NAME="i5"></TD></TR>

<TR><TD WIDTH=10%>&nbsp;</TD>
<TD ALIGN=RIGHT WIDTH=45%><P>Dynamic HTML: <INPUT TYPE="CHECKBOX" NAME="i6"></TD>
<TD ALIGN=RIGHT WIDTH=45%><P>Style Sheets: <INPUT TYPE="CHECKBOX" NAME="i7"></TD></TR>
</TABLE>

<HR>

<P><TABLE WIDTH=100%><TR><TD ALIGN=RIGHT><P>
<INPUT TYPE="RESET" VALUE="Default Profile">
<INPUT TYPE="SUBMIT" VALUE="Update Profile">
</TD></TR></TABLE>

</TD></TR></TABLE>
</FORM>

<P><SMALL><BR>The information you provide here will NOT be passed to any third party,
<BR>or used to send unsolicated email, or stored in a database.</SMALL>


<P><A HREF="index.htm">Return</A>

You can try out the above example.

References

Chocolate Chip Cookies

Accessing cookies via JavaScript by Bill Dortch

Official HTTP Cookie Spec or the Netscape version

Related items

Intelligent Cookies

Chocolate Chip Cookies + Automating NEW!

©2018 Martin Webb