2009-03-04 39 views
9

我写了一些Javascript以允许编辑HTML表单中的项目列表,包括添加和删除项目。知道它在Firefox中工作。在Internet Explorer中尝试它时,我发现任何添加的项目都没有与表单一起提交。IE没有提交;动态添加表单元素;这是一个IE错误?

长篇小说简短...大量简化,调试,找出哪些行触发IE忽略新的表单输入。所以行为问题解决了。

但现在我必须问:为什么?这是一个IE错误?

下面是简化的代码:

<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> 

要尝试一下,做明显的:负载在IE中,点击添加,点击提交,看看有什么在地址栏中。如果您取消注释add()中的最后一行,IE将突然停止报告field3。它可以在Firefox中正常工作。

任何想法?一个好奇的头脑想知道。 (以及如何在需要时添加文本,以便携式方式,因此IE很高兴?)

回答

7

这是一个IE错误吗?

似乎是这样。当您通过DOM方法创建一个< input>元素时,IE不会完全拾取'name'属性。这是因为元素确实提交了,但如果你试图获得元素的'innerHTML'表示,它就会神秘地消失。如果您通过直接写入到innerHTML来创建元素,则不会发生这种情况。

此外,如果您使用DOM级别0表单导航方法(如'myform.elements.x.value'),则通过'元素'数组访问可能不起作用(类似地,直接的'myform.x'访问某些人被错误地使用)。无论如何,这些日子你可能更喜欢getElementById()。

所以要么使用innerHTML 使用DOM方法;最好不要在创建表单域时混合它们。

这是documented (see ‘Remarks’)并最终在IE8中修复。

在任何情况下,永远不会做:

div.innerHTML + = '...';

这仅是为了语法糖:

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

换句话说,它有连载的元素的整个子HTML内容,然后做字符串连接,然后重新解析新的字符串回元素,扔掉所有的原始内容。这意味着你失去了无法序列化的东西:IE的伪造的半创建的'name'属性也意味着你已经附加到每个子元素的任何JavaScript事件处理程序,DOM侦听器或其他自定义属性。另外,不必要的序列化/解析循环很慢。

3

IE在运行时更改某些内置属性非常挑剔。例如,输入元素的名称在设置时不能更改。

两件事情,如果我是你,我会尝试:

  1. 而不是使用setAttribute(),尽量明确地设置nametypevalue属性:

    e.name = "text";

  2. 如果没有按不起作用,您可能必须将所有这些属性包含在document.createElement()调用中:

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

    这实际上可能会在某些浏览器中引发异常。所以最好的跨浏览器的方式是:

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'; 
+0

1上避免的setAttribute。 -1的createElement-with-markup调用,这是一个非常丑陋的IE浏览器只有黑客。 – bobince 2009-03-04 19:22:18

+0

我同意这是一个黑客 - 这就是为什么我建议海报先尝试设置属性。如果这不起作用,我看不到另一种方式来实现他想要发生的事情。 – levik 2009-03-04 19:36:03

3

谢谢bobince和levik为你解答。使用这些和一些更多的实验,这里是我的结论:

  1. 是的,这是一个IE错误。

  2. IE 8修复了根据Microsoft的错误:“Internet Explorer 8及更高版本可以在运行时使用createElement方法动态创建的元素上设置NAME属性。”

  3. 问题是这样的:调用e.setAttribute("name", "field3")只有设置名称。如果元素没有发生任何其他事情,它将工作,但如果请求序列化,则名称不会被序列化。所以当我说innerHTML += " "强制序列化,失去了名称,所以它并没有在反序列化时被恢复。没有名字,没有包含在表单提交中。

  4. 解决方法#1:e = document.createElement("<input name='field3' />")即使在面对序列化时也能正常工作。

  5. 解决方法#2:与其使用innerHTML + =添加文本,我可以附加如下文本元素:div.appendChild(document.createTextNode(" "));。我认为必须有更好的方法来添加文本,现在我知道了:-)。

干杯,
--jsf