-
-
Save mmonteleone/1209097 to your computer and use it in GitHub Desktop.
<!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> |
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
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
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.
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.
You are reading the
checked
property in your code here, not the checked attribute.Checkbox and radio "checked" attribute is read via "getAttribute"; its corresponding boolean value can be read via its
defaultChecked
property.