Inconsistency in jQuery's attribute manipulation
-
21-09-2019 - |
Question
$('<option selected="selected">something</option>')
.removeAttr('selected')
.wrap('<p></p>').parent().html();
results in
<option>something</option>
which is expected. But if I put back the 'selected' attribute after removing it (or to an <option>
tag without 'selected' attribute), I get the same output.
$('<option selected="selected">something</option>')
.removeAttr('selected')
.attr('selected', 'selected')
.wrap('<p></p>').parent().html();
Why is this happening?
Solution
There are two selected
s, the selected
attribute and the selected
property.
The HTML selected="selected"
attribute sets the initial state of the JavaScript selected
boolean property, but after that, like all form field state, they are independent.
If you select the option by clicking on it in the select box, it doesn't add an HTML selected="selected"
attribute to the HTMLOptionElement DOM node, so you won't see that reflected in the innerHTML
/html()
of the element. Instead it just sets the underlying form contents as reflected by the option.selected
property.
IE before version 8 doesn't even allow you to set the HTML selected
attribute, because setAttribute
is broken there. If you try, it'll actually set the selected
boolean property.
attr()
in jQuery is a kind of hybrid of attribute and property access which tries to sweep these problems under the rug. But the upshot is calling attr('selected')
is effectively the same as using the boolean selected
property.
OTHER TIPS
First, an <option>
shouldn't be wrapped in a paragraph - this could account for some weird behavior you're seeing. Also, the "selected" attribute might not be expressed in the HTML markup but it is being set where it counts - i.e. the DOM "selected" property.
var option = $('<option selected="selected">something</option>');
option.removeAttr('selected').attr('selected', 'selected');
option[0].selected === true;
seeing this analysis, which can be seen in the DOM is that it is selected the item, but the text of HTML can not be seen.
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
<script language="JavaScript">
$(function(){
var opc0 = document.createElement("option");
var theText = document.createTextNode("something 0");
opc0.appendChild(theText)
opc0.setAttribute("selected", "selected");
opc0.removeAttribute("selected");
opc0.setAttribute("selected", "selected");
var opc1 = $("<option value=\"test\" label=\"tlabel\" selected=\"selected\">something 1</option>");
opc1.removeAttr("label");
opc1.removeAttr("selected");
opc1.attr("selected", "selected");
opc1.attr("label", "tlabel2");
var opc2 = $("<option label=\"tlabel\" selected=\"selected\">something 2</option>");
opc2.removeAttr("selected")
var opc3 = $("<select id=\"selectTest\"></select>");
var opc3a = $("<option value=\"a\" selected=\"selected\">something 3 a</option>");
var opc3b = $("<option value=\"b\">something 3 b</option>");
var opc3c = $("<option value=\"c\">something 3 c</option>");
var opc3d = $("<option value=\"d\">something 3 d</option>");
var opc3e = $("<option value=\"e\">something 3 e</option>");
var opc3f = $("<option value=\"f\">something 3 f</option>");
opc3.append(opc3a);
opc3.append(opc3b);
opc3.append(opc3c);
opc3.append(opc3d);
opc3.append(opc3e);
opc3.append(opc3f);
opc3a.removeAttr("selected");
opc3.val("a");
var html0 = opc0.outerHTML;
var html1 = opc1.parent().html();
var html2 = opc2.parent().html();
var html3 = opc3.parent().html();
$("#preTest0").text(html0); //ok
$("#preTest1").text(html1); //err
$("#preTest2").text(html2); //ok
$("#preTest3").text(html3); //err
$(document.body)
.append(opc1)
.append(opc3);
$("#selectTest option:eq(4)").attr("selected","selected");
$("#selectTest option:selected").each(function () { $("#preTest5").text( $("#preTest5").text() + $(this).text() + " is selected "); });
var html4 = opc3.html();
$("#preTest4").text(html4); //ok accion, err html view
});
</script>
</head>
<body>
<pre id="preTest0"></pre><br />
<pre id="preTest1"></pre><br />
<pre id="preTest2"></pre><br />
<pre id="preTest3"></pre><br />
<pre id="preTest4"></pre><br />
<pre id="preTest5"></pre><br />
</body>
</html>