Microsoft KB Archive/256228

From BetaArchive Wiki
Knowledge Base


How To Make Script Element Behaviors Participate in Forms Submission

Article ID: 256228

Article Last Modified on 5/11/2006



APPLIES TO

  • Microsoft Internet Explorer 5.5



This article was previously published under Q256228

SUMMARY

It is common to want to use the new element behaviors in Internet Explorer 5.5 to create subclassed or grouped form elements. A developer might want to tie several text fields together into a generic and globalization-aware address behavior, for example, or create a dependent drop-down behavior. These new form elements must have some ways to participate in forms submission, so that their value fields can be injected into the form in which they are hosted and submitted with the rest of the form's data. While this is easy to do for a binary element behavior, it's not so obvious how to do this for a script element behavior.

MORE INFORMATION

Developers who write binary element behaviors for Internet Explorer 5.5 can make their behaviors participate in forms submission through the use of the IElementBehaviorSubmit interface.

Script-based (Microsoft JScript or Visual Basic Script [VBScript]) access to this mechanism is not currently supported in IE 5.5. Element behavior developers can add some simple code to a property, however, that will inject hidden fields into the element's hosting form.

The following code snippet demonstrates this technique for an element behavior composed of a SELECT box and an INPUT TEXT box. This simple behavior only displays the INPUT TEXT box if the currently selected option is Other. Whenever one of these values changes, the result is injected into the hosting form. The heart of this functionality is wrapped in the private methods injectIntoForm() and setFormElement(). These functions use createElement() to create new INPUT TYPE=HIDDEN elements and attach them to the form (if they have not already been defined).

Another area to pay attention to is the Load() function, which fires when the onDocumentReady event fires for the element behavior's hosting page. This code traverses the object hierarchy up from the element until it finds the form that is hosting it. This is necessary for the following reasons:

  • Your element behavior might be nested inside of another element behavior.
  • Your element behavior might be nested inside of another HTML element. For example, you might be using TABLE tags to format the contents of the FORM.
  • Unary tags in the form, like

    , will actually be treated by Internet Explorer as closed tags that don't terminate until the ending </BODY> tag of the element behavior's viewlinked content is reached. In other words, your element might be contained in another tag without you realizing it.

You can follow these steps to test the behavior sample:

  1. Create a page for the behavior called formsubclass.htc with the following code:

    <!--
    
    A simple subclassed INPUT TEXT element behavior that injects its values into the form in 
    which it is hosted. This slightly breaks encapsulation, but is currently necessary because
    script-based element behaviors in IE5.5 can't participate in forms submission. 
    
    NOTES
    
    - The Name property is necessary for the name used in the HTML file for the tag to be
      reflected internally on the element object. Without this property definition, we will
      not be able to get the name the user assigns to us. The same is true for ID, if you want
      ID to be defined on the element object.
    
    -->
    
    <PUBLIC:Component TagName="InputSubclass">
       <PUBLIC:DEFAULTS viewLinkContent tabStop/>
       <PUBLIC:PROPERTY NAME="name" INTERNALNAME="intName"/>
       <PUBLIC:ATTACH event="ondocumentready" onevent="Load();"/>
    
    <SCRIPT>
    
    var intName;
    
    var formElem;
    
    function Load() {
        // We need to climb the hierarchy from element.parentElement upwards until we
        // find the FORM element. 
        var elemTmp = element.parentElement;
        while (!(elemTmp.tagName).match(/FORM/i) && !((elemTmp.tagName).match(/HTML/i))) {
            elemTmp = elemTmp.parentElement;
            alert("Element is " + elemTmp.tagName);
        }
        if (elemTmp.tagName.match(/HTML/i)) {
            var err = new Error();
            err.description = "This element must be hosted inside of a FORM.";
            throw(err);
        }
    
        formElem = elemTmp;
    }
    
    // PRIVATE: injectIntoForm
    // Insert into the form in which we're hosted as a hidden element. Create a name
    // dynamically, based on the tag name of the current element instance, so that
    // we can host multiple instances of this element behavior inside the same form.
    
    function injectIntoForm() { 
        setFormElement(element.name + "_HowHeard", sel1.options(sel1.selectedIndex).value);
        setFormElement(element.name + "_HowHeardOther", txt1.value);
    }
    
    // PRIVATE: setFormElement
    
    function setFormElement (elemFormName, value) {
        // Test if the element already exists; create it if it doesn't.
        // Adding with appendChild() does not allow us to look up in the collection
        // by name. 
        var elemExists = formElem.elements(elemFormName);
        if (elemExists == null) {
            var newElem = element.document.parentWindow.document.createElement("INPUT");
            newElem.type = "hidden";
            newElem.name = elemFormName;
            // If you don't set ID, you won't be able to access this element using hash
            // retrieval from the elements collection.
            newElem.id = elemFormName;
            newElem.value = value;
            formElem.appendChild(newElem);
        } else {
            formElem.elements[elemFormName].value = value;
        }
    }
    
    // PRIVATE: sel1_onchange
    
    function sel1_onchange() {
        if (sel1.options(sel1.selectedIndex).value == 3) {
            txt1.disabled = false;
            txt1.style.backgroundColor = "white";
        } else {
            txt1.disabled = true;
            txt1.style.backgroundColor = "gray";
            // If the user had already typed in data for other, blow it away.
            if (formElem.elements(element.name + "_HowHeardOther") != null) {
            formElem.elements(element.name + "_HowHeardOther").value = "";
            txt1.value = "";
            }
        }
        // For simplicity, we'll assume txt1 isn't a required field, and that the user
        // can submit "other" without it.
        injectIntoForm();
    }
    
    // PRIVATE: txt1_onchange
    
    function txt1_onchange() {
        injectIntoForm();
    }
    
    
    </SCRIPT>
    
    <body>
    
    <SELECT name="sel1" onchange="sel1_onchange();">
    <option value="0">TV Advertisement
    <option value="1">Magazine Advertisement
    <option value="2">Word of Mouth
    <option value="3">Other
    </SELECT>
    
    <input type="text" size="20" name="txt1" value="" 
    style="background-color:gray;"  disabled="true"
    onchange="txt1_onchange();">
    
    </body>
    
    </PUBLIC:COMPONENT>
    
                        
  2. Create an html page called TestKB.htm that contains the following content to test the behavior:

    <HTML XMLNS:FormsTools>
    
    <head>
    <title>Other Select Box Sample</title>
    <?IMPORT namespace="FormsTools" implementation="formSubclass.htc"/>
    
    <SCRIPT>
    
    function showFormValues() {
        var txt = "";
    
        for (i = 0; i < document.frm1.length; i++) {
            txt += document.frm1(i).id + ": " + document.frm1(i).value + "<BR>";
        }
        document.all("div1").innerHTML = txt;
    }
    
    </SCRIPT>
    </head>
    <body>
    <form name="frm1" action="some page" method="GET">
    What is your name? <br>
    <input type="text" id="txtName" name="txtName" size="20">
    <p>
    
    
    How did you hear about us?<br>
    
    <FormsTools:InputSubclass Name="Input1">
    </FormsTools:InputSubclass><p>
    
    Current form values:
    <DIV id="div1">
    </DIV>
    
    <button id="btn1" onclick="showFormValues();">
    Display Current Form Values
    </button><p>
    
    </form>
    
    </body>
    
    </html>
                        
  3. Use Internet Explorer 5.5 to navigate to TestKB.htm.
  4. Type some text in the text box and change your selection in the drop-down list.
  5. Click Display Current Form Values and you will see that the values of the element behavior are included in the form collection.


REFERENCES

MSDN Online Web Workshop, Element Behaviors in Internet Explorer 5.5


For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:



Keywords: kbdhtml kbhowto KB256228