Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » HTML <form> POST

Credits go to Matthew Leverton for helping out!
This thread is locked; no one can reply to it. rss feed Print
HTML <form> POST
bamccaig
Member #7,536
July 2006
avatar

I have a form that is largely created using DHTML. I can't show exact code unfortunately, but I can give examples of what is happening... Obviously I haven't mastered the right way to do things yet... I'm still using tables to layout the Web page.

1include("dhtml.js");
2 
3function select_onChangeHandler(event)
4{
5 alert("selected option changed!");
6}
7 
8function addRecord(intExampleValue1, intExampleValue2, strExampleValue3)
9{
10 var i = document.getElementById("hidRecordCount").value|0;
11 /*
12 * Rather than create a ton of nameless variables or one-time-use variables
13 * I'm using an array to store references in.
14 */
15 var o = new Array();
16 
17 intExampleValue1 = (isNaN(intExampleValue1) ? (-1) : (intExampleValue1|0));
18 intExampleValue2 = intExampleValue2|0;
19 strExampleValue3 = String(strExampleValue3);
20 
21 // Get reference to tbody.
22 o[0] = document.getElementById("tbody-id_of_table_of_form");
23 {
24 // Create tr (representing a "record").
25 o[1] = createTR();
26 {
27 // Create td.
28 o[2] = createTD();
29 {
30 // Append hidden input.
31 o[2].appendChild(createHiddenInput("hidExampleID1|" + i, intExampleValue1));
32 
33 /*
34 * Create select (there are other parameters to these functions,
35 * for example, to create options and add them to the select, but
36 * they're irrelevant to this thread).
37 */
38 o[3] = createSelect("selExampleID2|" + i, intExampleValue2);
39 {
40 addListener(o[3], "change", select_onChangeHandler, false);
41 }
42 
43 // Append select.
44 o[2].appendChild(o[3]);
45 
46 // Append hidden input.
47 o[2].appendChild(createHiddenInput("hidExampleID3|" + i, strExampleValue3));
48 
49// Etc...
50 }
51 
52 // Append td.
53 o[1].appendChild(o[2]);
54 
55// Etc...
56 }
57 
58 // Append tr.
59 o[0].appendChild(o[1]);
60 }
61 
62/*
63 * DEBUG EXAMPLE
64 */
65 
66// Where hidExampleID1 is the problem field.
67alert(document.getElementById("hidExampleID1|" + i).value); // This works...
68 
69/*
70 * DEBUG EXAMPLE
71 */
72 
73 // Update count.
74 document.getElementById("hidRecordCount").value = (i+1);
75}

Everything works as expected client-side and all fields exist. I can use the IEDeveloperToolbar to see them and check their values. I can also use JavaScript to see their values on events, for example. I can use Microsoft's Script Debugger to walk the node tree and link the fields to the <form>, which is a parent of the table the tbody is in.

When I submit the form, all the fields appear to post except for one. It's a hidden input and I can't explain why it doesn't post... :-/ The field exists on the client. Using Microsoft's Script Debugger I have traced it back to the form element (.parentElement.parentElement.parentElement...). I assumed I have the field name wrong, but I switched the HTTP method to GET and went through the variables in the query string and the same field was missing...

Does anybody have any guesses why this one field refuses to be sent?

Matthew Leverton
Supreme Loser
January 1999
avatar

Does it work in a better browser?

bamccaig
Member #7,536
July 2006
avatar

Matthew Leverton
Supreme Loser
January 1999
avatar

In that case, I blame IE's DHTML. Try copy/pasting the generated HTML code into a static HTML file and submitting that in IE. If it works, then you know it's a DHTML bug. If it doesn't, you can fiddle with that static HTML file until it works.

bamccaig
Member #7,536
July 2006
avatar

I figured out the problem. Now I know why not to use the innerHTML property. :-X

1// Create td.
2o[2] = createTD();
3{
4 // Append hidden input.
5 o[2].appendChild(createHiddenInput("hidExampleID1|" + i, intExampleValue1));
6 
7 /*
8 * Create select (there are other parameters to these functions,
9 * for example, to create options and add them to the select, but
10 * they're irrelevant to this thread).
11 */
12 o[3] = createSelect("selExampleID2|" + i, intExampleValue2);
13 {
14 addListener(o[3], "change", select_onChangeHandler, false);
15 }
16 
17 // Append select.
18 o[2].appendChild(o[3]);
19 
20 // Append space.
21 o[2].innerHTML += " ";
22 
23/* **ERROR**
24 * IE doesn't send fields that were appended before the nbsp. The client works
25 * fine, but the server doesn't receive the fields appended to the <td> above.
26 * **ERROR**
27 */
28 
29 // Append hidden input.
30 o[2].appendChild(createHiddenInput("hidExampleID3|" + i, strExampleValue3));
31 
32// Etc...
33}

The solution was to instead append a text node.

// Append space.
o[2].appendChild(document.createTextNode(" "));

// OR if you wrap it like I did...

/*
 * Append space. createSpaceNode() accepts an optional parameter, intCount, to
 * create a text node with multiple spaces.
 */
o[2].appendChild(createSpaceNode());

Matthew Leverton
Supreme Loser
January 1999
avatar

Quote:

Now I know why IE sucks.

Corrected.

It's usually best to create all input elements with document.createElement(), then set the type before you do anything else.

Also, IE has quirks where you must do something like document.createElement('<form enctype="blah">'); if you ever want to set the enctype property, because if you do it after the form is created it won't honor it. ::)

bamccaig
Member #7,536
July 2006
avatar

Matthew Leverton said:

Also, IE has quirks where you must do something like document.createElement('<form enctype="blah">'); if you ever want to set the enctype property, because if you do it after the form is created it won't honor it. ::)

Yeah, the same is true of checkboxes' initial checked property. ::) I found that out the hard way. createCheckboxInput() looks something like...

function createCheckboxInput(id, checked, options)
{
    var e = ((navigator.appName == "Microsoft Internet Explorer") ? ("<input" + ((checked) ? (" checked") : ("")) + ">") : ("input"));
    var o = {checked:checked, id:id, name:id, type:"checkbox"};

    if(options != null)
        o = augment(o, options);

    return(createElement(e, o));
}

In other words,...

document.createElement("<input checked>"); // IE
document.createElement("input"); // !IE

:D

I'm sure there is a more reliable way to check the browser (and it might help to check the browser version as well, assuming IE8 actually works)... Meh. I haven't tested IE6 yet so I might just need to make more workarounds for it, such as the type property... :-/

Matthew Leverton
Supreme Loser
January 1999
avatar

That's an evil way... This is better for the times when IE is broken:

var e;
try {
  e = document.createElement("<input checked>");
} catch (foo) {
  e = document.createElement("input");
  e.type = "checked";
}

bamccaig
Member #7,536
July 2006
avatar

Matthew Leverton said:

That's an evil way... This is better for the times when IE is broken...

That certainly looks nicer, but it doesn't account for an unchecked checkbox in IE. I guess this would work...

var e;
try {
  checked = (checked ? " checked" : "");
  e = document.createElement("<input" + checked + ">");
} catch (foo) {
  e = document.createElement("input");
  e.type = "checked";
}

** EDIT **

That's not working in IE (or I did something wrong)... :( Technically even createElement is wrapped so my implementation is a little bit different.

** EDIT **

Yeah, I did something wrong. :P checked and blnChecked are not the same variable. ;)

On a side note, I think you meant e.type="checkbox"; and e.checked=checked;

Matthew Leverton
Supreme Loser
January 1999
avatar

Quote:

On a side note, I think you meant e.type="checkbox"; and e.checked=checked;

Yeah, basically in the try goes the minimum that IE requires and in the catch goes the same thing for compliant browsers. Then after you can set the common things.

bamccaig
Member #7,536
July 2006
avatar

OK, fixed. Of course, I did something wrong. :-[ I was using checked instead of blnChecked. :) I've been doing something like this...

1function createCheckboxInput(strID, blnChecked, objConfig)
2{
3 var o = {checked:Boolean(blnChecked), id:String(strID), name:String(strID), type:"checkbox", value:1};
4 
5 if(objConfig != null)
6 o.augment(objConfig);
7 
8 try
9 {return(createElement("<input" + (Boolean(blnChecked) ? " checked" : "") + ">", o));}
10 catch(e)
11 {return(createInput(o));}
12}
13 
14function createElement(strElement, objConfig)
15{
16 var o = document.createElement(strElement);
17 
18 if(objConfig != null)
19 o = augment(o, objConfig);
20 
21 return(o);
22}
23 
24function createInput(objConfig)
25{
26 return(createElement("input", objConfig));
27}

I said:

I haven't tested IE6 yet so I might just need to make more workarounds for it, such as the type property... :-/

Actually, it appears to be working in IE6 as well. :D8-)

Go to: