IE6 & IE7 quirks with cloneNode() and form elements

Categories: jQuery, JavaScript

I've been working on some code for a contracting client which involves a really cool drag-n-drop interface for building forms on-the-fly. While working on the project, I ran into an issue in IE6 when dragging a <div /> element that form fields and there values had been changed by the user, the values were not properly reflected when I'd copy the node using the cloneNode() DOM method.

It turns out IE 6/7 doesn't properly clone some form elements when you use the cloneNode(true) and the form element is a checkbox, radio or select element. My suspicion is this is because MSIE stores the element in a non-XHTML way (if you do an innerHTML on the source element you'll see that checkbox elements have a "CHECKED" attribute with no value.)

I was able to work around the issue by doing the following:

var clonedEl = elm.cloneNode(true);
/*
* if this is MSIE 6/7, then we need to copy the innerHTML to
* fix a bug related to some form field elements
*/

if( !!document.all ) clonedEl.innerHTML = elm.innerHTML;

The project I'm working on is actually using the jQuery Interface v1.2 library. To fix the problem I actually had to modify the source code in the Draggables to find instances of the cloneNode(true) method and apply the fix.

NOTE:
The actual fix I used in jQuery varies slightly, as I used available jQuery methods to detect IE6. In jQuery you can do:
var clonedEl = elm.cloneNode(true);
/*
* if this is MSIE 6/7, then we need to copy the innerHTML to
* fix a bug related to some form field elements
*/

if( jQuery.browser.msie && (jQuery.browser.version <= 7) )
    clonedEl.innerHTML = elm.innerHTML;

This quite frankly feels like an issue I've run into before, but just forgot the solution. Hopefully blogging about it well help me if I ever run into the problem again.

UPDATE:

I've added an example page that shows this problem off in action: http://www.pengoworks.com/workshop/bugs/cloneNode_issue.htm

Comments

VulgarisOverIP's Gravatar Thank you so much, you've stopped the hours of torture.
Santiago's Gravatar Thanks man, this was a big help for me.
Erik's Gravatar Thanks for this post. I just ran into this problem, but I wanted to note that this solution does not quite work in Firefox. It seems that once you copy the innerHTML to the cloned element, Firefox loses the attributes (what IE was doing before we copied innerHTML). So to get around this I resorted to sniffing for IE before copying the innerHTML. Am I missing something here? Does anyone know if Prototype or jQuery have a cross-platform method for this built in? For instance, try using your example form in Firefox (2.0 here) -- the first clone method works fine, but the second one ('w/fix') doesn't copy the attributes.
Dan G. Switzer, II's Gravatar @Erik:

If you read the blog entry, you'll see that I only apply that to IE6. The test page was purely to illustrate the problem that IE has. You should only apply the fix to IE6.

I believe jQuery might have since worked in a fix for this, but I haven't looked at the clone() in a while.
Duncan's Gravatar I wanted to say....cheers for posting that trick with "clonedEl.innerHTML = elm.innerHTML" - I was just starting to despair when faced with the prospect of rewriting a ton of code to make it work in IE7....now everythings working great.
Duncan's Gravatar The next problem I hit is that cloned INPUT and SELECT elements don't seem to be accessable using document.form.<name>. I updated the name attribute on each cloned INPUT and SELECT to give it a unique name but it's as if the new names are not entered as properties of the form. Workaround: after cloning the node execute "document.form1[<new name>]=<cloned INPUT/SELECT>;" to explicitly add them. No need in Firefox of course, just IE.
Hans's Gravatar Do you also have a fix for ie8?
Jens's Gravatar selectbox value does not transfer in Example page in Firefox 3.6.10
Nkey's Gravatar Thanks you a lot, man!

Add Comment

Leave this field empty


If you subscribe, any new posts to this thread will be sent to your email address.