Skip to content

Instantly share code, notes, and snippets.

@mmonteleone
Created September 11, 2011 02:40
Show Gist options
  • Save mmonteleone/1209097 to your computer and use it in GitHub Desktop.
Save mmonteleone/1209097 to your computer and use it in GitHub Desktop.
Cloned Radio Input Checked State Test
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Radio Clone Test</title>
<script type="text/javascript">
/* Example of checked state of a radio input not being retained in a twice-cloned node.
Fails in Safari 4.0.5.
Passes in 5.1 */
window.onload = function() {
var div = document.createElement("div");
div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
var fragment = document.createDocumentFragment();
fragment.appendChild(div.firstChild);
var fragCloneClone = fragment.cloneNode(true).cloneNode(true).lastChild;
alert('Cloned check state retained (expected true): ' + fragCloneClone.checked);
document.getElementById('formtest').appendChild(fragCloneClone);
}
</script>
</head>
<body>
<form id="formtest"></form>
</body>
</html>
@mmonteleone
Copy link
Author

Example of checked state of a radio input not being retained in a twice-cloned node.

Affects Safari 4.0.5. Does not affect 5.1

@mmonteleone
Copy link
Author

Related to this commit thread

@GarrettS
Copy link

You are reading the checked property in your code here, not the checked attribute.

alert('Cloned check state retained: ' + 
  fragment.cloneNode(true).cloneNode(true).lastChild.checked);

Checkbox and radio "checked" attribute is read via "getAttribute"; its corresponding boolean value can be read via its defaultChecked property.

var fragCloneClone = fragment.cloneNode(true).cloneNode(true);
alert('Cloned checked attribute value (expect true): ' + fragCloneClone.lastChild.defaultChecked);

@mmonteleone
Copy link
Author

This is a valid point. I've updated the gist to demonstrate that even when not specifically reading checked or defaultChecked, the cloned fragment, when appended to the DOM, does not remain checked. Again, this passes Safari 5, but not Safari 4

@GarrettS
Copy link

That behavior isn't really surprising.

Invalid "bugs" about cloneNode not preserving element such that when the element is cloned, show wanting the current state the element has to be cloned with it, including event handlers and other DOM properties (like checked). For example:
Bug 230307 - user input/selection not preserved on cloned HTML textarea and select elements, where a commenter posted:

var sel = document.createElement('SELECT')
var opt1 = document.createElement('OPTION')
var opt2 = document.createElement('OPTION')
opt1.value = 'A'
// A
opt2.value = 'B'
// B
opt1.selected = opt1.defaultSelected = true
// true
sel.appendChild(opt1)
// [object HTMLOptionElement]
sel.appendChild(opt2)
// [object HTMLOptionElement]
opt2.selected = true
// true
var clone = sel.cloneNode(true)
[clone.value, sel.value]
A,B

And the result shown is right; cloneNode operation cloned the attributes not properties. But what the commenter wanted was for the properties to be cloned instead. He wrote: "The expected output is B,B" -- a false expectation.

I realize this is a different case. In your case, you have an INPUT whose attribute is checked and that somehow the state of the input is reset upon cloning it.

But there have been numerous other bugs related to state not being cloned, so I wouldn't bet on it working 100%.

This problem has shown up in jQuery devs before with its clone function.
Searching...

...found more than I thought I would, actually.

http://bugs.jquery.com/ticket/6486
http://bugs.jquery.com/ticket/5758

http://bugs.jquery.com/ticket/3879
This one, too, but there are a few problems, and the comments are ah, well, talking about the slowness of traversing the children of checkboxes:
http://bugs.jquery.com/ticket/769

@mmonteleone
Copy link
Author

I follow your examples and agree with your analyses. This bug is different than the ones you linked, as it is not regarding a mistaken attempt to clone a node's properties, handlers, etc, but simply its attributes as populated by innerHTML.

The bug fix wasn't an advocation of the questionable practices of using cloneNode alongside innerHTML, but only as a fix for a blocking issue I had with jQuery 1.4, which simply provided no choice as it uses cloneNode internally within its innerHTML wrapper's node cache. Nor was it regarding jQuery's own clone function.

@GarrettS
Copy link

No, look closely at my example using defaultChecked; the "checked" attribute is indeed copied, resulting in defaultChecked == true. Also try:

var fragCloneClone = fragment.cloneNode(true).cloneNode(true);
alert('Cloned checked attribute value (expect true): ' + fragCloneClone.lastChild.getAttribute("checked"));

Results "checked".

So the cloning is working fine. The checkbox is cloned, the checked attribute is cloned.

The state of the object is being lost. That's not the same thing as the attribute being lost.

But why does that happen? Is that a bug? When I remove the element's name it retains the state; input.checked is true and it can be seen in the document that it is ticked off.

<script type="text/javascript">
window.onload = function() { 
    var div = document.createElement("div");
    div.innerHTML = "<input type='radio' id='radiotest' checked='checked'>";
    var fragment = document.createDocumentFragment();
    fragment.appendChild(div.firstChild);
    var fragCloneClone = fragment.cloneNode(true).cloneNode(true).lastChild;
    alert('Cloned check state retained (expected true): ' + fragCloneClone.checked);
    document.getElementById('formtest').appendChild(fragCloneClone);
}
</script>

alerts "true" and the radio looks checked. Also, this does not affect checkboxes; only radios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment