views:

1365

answers:

3

I wrote some Javascript to allow editing a list of items within an HTML form, including adding and removing items. Got it working in Firefox. When trying it in Internet Explorer, I found that any added items were not being submitted with the form.

Long story short... lots of simplification, debugging, figured out what line is triggering IE to ignore the new form input. So the behavior problem is solved.

But now I must ask: Why? Is this an IE bug?

Here is the simplified code:

<html>
<head>
    <title>Test</title>
    <script type="text/javascript">
        function add() {
            div = document.getElementById("mylist");

            // *** Adding text here works perfectly fine. ***
            div.innerHTML += " ";

            e = document.createElement("input");
            e.setAttribute("type", "text");
            e.setAttribute("name", "field3");
            e.setAttribute("value", "--NEWVALUE--");
            div.appendChild(e);

            // *** Adding text here works perfectly fine in Firefox, but for
            //     Internet Explorer it causes field3 to not be submitted. ***
            //div.innerHTML += " ";
        }
    </script>
</head>
<body>
    <form action="" method="get">
        <div id="mylist">
            <input type="text" name="field1" value="value1" />
            <input type="text" name="field2" value="value2" />
        </div>
        <a href="javascript:" onclick="add()" />Add</a>
        <input type="submit" value="Submit" />
    </form>
</body>
</html>

To try it out, do the obvious: load in IE, click Add, click Submit, look what's in the address bar. If you uncomment the last line in add(), IE will suddenly stop reporting field3. It works fine either way in Firefox.

Any ideas? A curious mind wants to know. (And how would I add text there if needed, in a portable fashion, so IE is happy?)

+1  A: 

IE is very picky about changing some built-in properties at runtime. For example, the name of an input element cannot be changed while set.

Two things I would try if I were you:

  1. Instead of using setAttribute(), try setting the name, type and value properties explicitly:

    e.name = "text";

  2. If this doesn't work, you may have to include all these attributes into the document.createElement() call:

    var e = document.createElement("<input type='text' name='field'>");

    this may actually throw an exception in some browsers. So the best cross browser way to go would be:

.

var e;
  try {
    e = document.createElement("<input type='text' name='field'>");
  } catch (ex) {
    e = document.createElement("input");
    e.type = 'text';
    e.name = 'field';
  }
  e.value = 'value';
levik
+1 on avoiding setAttribute. -1 on the createElement-with-markup call which is an egregiously ugly IE-only hack.
bobince
I agree about it being a hack - which is why I'm suggesting the poster try setting properties first. If that doesn't work, I don't see another way to make what he wants happen.
levik
+2  A: 

Is this an IE bug?

Seems so. When you create an <input> element through DOM methods, IE doesn't quite pick up the ‘name’ attribute. It's sort-of-there in that the element does submit, but if you try to get an ‘innerHTML’ representation of the element it mysteriously vanishes. This doesn't happen if you create the element by writing directly to innerHTML.

Also if you use DOM Level 0 form navigation methods, like ‘myform.elements.x.value’, access through the ‘elements’ array may not work (similarly the direct ‘myform.x’ access some people misguidedly use). In any case these days you might prefer getElementById().

So either use innerHTML or use DOM methods; best not to mix them when creating form fields.

This is documented (see ‘Remarks’) and finally fixed in IE8.

In any case, never do:

div.innerHTML+= '...';

This is only syntactical sugar for:

div.innerHTML= div.innerHTML+'...';

In other words it has to serialise the entire child HTML content of the element, then do the string concatenation, then re-parse the new string back into the element, throwing away all the original content. That means you lose anything that can't be serialised: as well as IE's bogus half-created ‘name’ attributes that also means any JavaScript event handlers, DOM Listeners or other custom properties you have attached to each child element. Also, the unnecessary serialise/parse cycle is slow.

bobince
+1  A: 

Thank you bobince and levik for your answers. Using those, and some more experimentation, here are my conclusions:

  1. Yes it is an IE bug.

  2. IE 8 fixes the bug according to Microsoft: "Internet Explorer 8 and later can set the NAME attribute at run time on elements dynamically created with the createElement method."

  3. The bug is this: Calling e.setAttribute("name", "field3") only kind-of sets the name. It will work if nothing else happens to the element, but if requested to serialize, the name is not serialized. So when I said innerHTML += " " that forced a serialization, which lost the name, so it was not recovered upon deserialization. No name, no inclusion in form submission.

  4. Workaround #1: e = document.createElement("<input name='field3' />") would work, even when faced with serialization.

  5. Workaround #2: Rather than adding text using innerHTML +=, I can append a text element like this: div.appendChild(document.createTextNode(" "));. I had figured there must be a better way of adding text, and now I know it :-).

Cheers,
--jsf

Jeremy Frank