[ Team LiB ] Previous Section Next Section

8.14 Copying Form Data Between Pages

NN 4, IE 4

8.14.1 Problem

You want to convey all form control settings from one page to another.

8.14.2 Solution

Use the stringForms.js library shown in the Discussion to convert all values in a form to a string that can be passed to another page via URLs or cookies. Invoke the form2ArrayString( ) function, passing as an argument a reference to the form in need of conversion. The function returns a string whose format is of a shortcut constructor of an array of objects. Each object represents a form control in the following format:

{name:'elemName',id:'elemID',type:'elemType',value:value}

To distribute the values to a form with the same control structure, invoke string2FormObj( ), passing parameters for a reference to the destination form and to the string originally created by the form2ArrayString( ) function.

8.14.3 Discussion

Example 8-3 shows the code for the stringForms.js library (applied in Recipe 10.6). The library provides two main functions that your scripts invoke: form2ArrayString( ), which converts a form's content to a string formatted like a JavaScript array of objects, and string2FormObj( ), which copies values from the array to form controls in another page that have the same names or IDs.

Example 8-3. The stringForms.js library
// Read the name, id, type, and value of one form control element
// as requested by form2ArrayString( )
function formObj2String(obj) {
    var output = "{";
    if (obj.name) {
        output += "name:'" + obj.name + "',";
    }
    if (obj.id) {
        output += "id:'" + obj.id + "',";
    }
    output += "type:'" + obj.type + "',";
    switch (obj.type) {
        case "radio":
            if (obj.name) {
                obj = document.forms[0].elements[obj.name];
                var radioVal = "value:false,index:-1";
                for (var i = 0; i < obj.length; i++) {
                    if (obj[i].checked) {
                        radioVal = "value:true,index:" + i;
                        i = obj.length;
                    } 
                }
                output += radioVal;
            } else {
                output += "value:" + obj.checked;
            }
            break;
        case "checkbox":
            output += "value:" + obj.checked;
            break;
        case "select-one":
            output += "value:" + obj.selectedIndex;
            break;
        case "select-multiple":
            output += "value:" + obj.selectedIndex;
            break;
        case "text":
            output += "value:'" + escape(obj.value) + "'";
            break;
        case "textarea":
            output += "value:'" + escape(obj.value) + "'";
            break;
        case "password":
            output += "value:'" + escape(obj.value) + "'";
            break;
        case "hidden":
            output += "value:'" + escape(obj.value) + "'";
            break;
        default:
            output += "";
    }
    output += "}"
    return output;
}
// Convert a passed form reference to a string formatted like
// a JavaScript array of objects
function form2ArrayString(form) {
    var elem, lastName = "";
    var output = "[";
    for (var i = 0; i < form.elements.length; i++) {
        elem = form.elements[i];
        if (elem.name && (elem.name != lastName)) {
            output += formObj2String(form.elements[i]) + ",";
            lastName = elem.name;
        }
    }
    output = output.substring(0, output.length-1) + "]";
    return output;
}
   
// Distribute form control values from another source to the
// controls in this page's form, whose names/ids match those
// of the original form controls
function string2FormObj(form, str) {
    var elem, objArray = eval(str);
    for (var i = 0; i < objArray.length; i++) {
        elem = (objArray[i].name) ? form.elements[objArray[i].name] : 
            document.getElementById(objArray[i].id);
        switch (objArray[i].type) {
            case "radio":
                if (objArray[i].name && objArray[i].value && objArray[i].index >= 0) {
                    elem = elem[objArray[i].index];
                }
                elem.checked = objArray[i].value;
                break;
            case "checkbox":
                elem.checked = objArray[i].value;
                break;
            case "select-one":
                elem.selectedIndex = objArray[i].value;
                break;
            case "select-multiple":
                elem.selectedIndex = objArray[i].value;
                break;
            default:
                elem.value = unescape(objArray[i].value);
        }
    }
}

The form2ArrayString( ) function manages the conversion process by iterating through all elements of a form. For each element, it invokes the support function, formObj2String( ), which does the hard work of this library. The purpose of the formObj2String( ) function is to convert basic specifications about a passed form control element to a string formatted as a shortcut object creation sequence. Each of these objects contains four properties: name, id, type, and value. Each control type that accepts user input and can be read without security violations is accounted for.

Your scripts invoke the form2ArrayString( ) function to obtain the string specification of the form's controls. Pass a reference to the form on the source page whose values you want to preserve. The function returns a string that looks like shortcut array notation. Each array entry is a string representation of an object whose properties define a single form control. This string may be passed as a search string in a URL or saved as a cookie for reading by another page from the same server and domain.

When it's time to reapply the values to a form on another page, use the string2FormObj( ) function of this library. Pass to this function a reference to the form on the current page and the string containing the array syntax. Although normally avoided for performance reasons, you need the eval( ) function here to convert the array string into an actual array object. Form controls with the same name (or, lacking a name, the ID) of the original form are populated with the same values reported previously. Other form controls with unique names are not disturbed.

While the stringForms.js library takes into account the peculiar ways that radio buttons share the same name, it does not preserve multiple selection values of a select-multiple type of select element. Instead, the function relies exclusively on the selectedIndex property of the element. You could modify the library to accommodate multiple selections by preserving the value as an array (in string format, of course) of options whose selected property is true.

The importance of preserving form specifications in string format becomes evident when you need to convey the data across pages. As described in Recipe 10.4 and Recipe 10.6, two of the three ways to pass data from one page to the next (URLs and cookies) require that the data be in string format. The JavaScript shortcut syntax for creating arrays and objects comes in very handy here, because the strings are very compact (compared to other kinds of formats) making it less likely that you'll overrun the 512-character limit of URLs, or the practical 1 KB limit of a single cookie value.

8.14.4 See Also

Recipe 3.1 and Recipe 3.8 for more about shortcut array and object creation syntax; Recipe 3.13 for a similar type of object-to-string conversion for custom objects; Recipe 10.4 for passing string data between pages via cookies; Recipe 10.6 for data passing via URL search strings.

    [ Team LiB ] Previous Section Next Section