12

Using jQuery when changing .html() of an <option> inside a <select> (Which I had previously set selectedIndex property to -1) resets selectedIndex property of <select> from '-1' to '0'

<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<select id="myselect" class="drpmnu">

   <option id="one" >(01)</option>

   <option id="two" >(02)</option>

   <option id="three" >(03)</option>

</select>
  <script>
    $(".drpmnu").prop('selectedIndex', -1)
    $('#three').html("moo")
  </script>
</body>
</html>

http://jsbin.com/filowe/2/edit?html,output

  • 1
    The best I can figure is that it is a repaint issue. When you change the text of the option is causes the select to repaint. In the repaint there is an issue where the prop gets reset to the default value. – Blake Plumb Feb 06 '15 at 20:23
  • `$('#three')[0].text="moo";` doesn't reset the index, but `textContent` does. – dandavis Feb 08 '15 at 04:15
  • @dandavis, `$('#three')[0].text="moo";` doesn't work in IE (at least in IE11) – Kiril Feb 08 '15 at 19:04
  • Just **don't use `.html()`** on ` – Bergi Feb 09 '15 at 14:41

4 Answers4

6

This case is mentioned in the HTML5 spec:

On setting, the selectedIndex attribute must set the selectedness of all the option elements in the list of options to false, and then the option element in the list of options whose index is the given new value, if any, must have its selectedness set to true and its dirtiness set to true.

Note: This can result in no element having a selectedness set to true even in the case of the select element having no multiple attribute and a display size of 1.

...

If nodes are inserted or nodes are removed causing the list of options to gain or lose one or more option elements, or if an option element in the list of options asks for a reset, then, if the select element's multiple attribute is absent, the select element's display size is 1, and no option elements in the select element's list of options have their selectedness set to true, the user agent must set the selectedness of the first option element in the list of options in tree order that is not disabled, if any, to true.

Changing an option via setting its innerHTML or textContent property triggers this reset (except on Firefox), but the text property (which is <option> only) does not trigger it (except on IE).

// these triggers the <select> element's reset (except on Firefox)
$("#three")[0].innerHTML   = "foo";
$("#three")[0].textContent = "foo";

// this does not trigger the reset (except on IE)
$("#three")[0].text = "foo";

Firefox follows the spec more strictly, it only resets the <select> if there is a new <option>, or there was a removal of one of the <option>s. But it fails to execute the reset during setting an <option>'s selected property to false (but that should trigger the reset too).

In short, all of the current browsers fail to implement the spec completely, so the only cross-platform workaround is to change selectedIndex as the last operation on a select (and its descendant elements):

$("#three").html("moo");
$(".drpmnu").prop("selectedIndex", -1);
Community
  • 1
  • 1
pozs
  • 34,608
  • 5
  • 57
  • 63
1

The behavior is different across various browsers. I just checked in firefox and it worked without any error. It shown me an empty dropdown and I checked the selected index was -1. The result was not same in Chrome though.

Ideally, -1 is used for select when no option is selected in starting. I am not sure if -1 can be set programmatically across all the browsers.

Changing option's HTML does not trigger the change event, if it would - the following code will end up running infinite loop.

var i = 0;
$(".drpmnu").change(function (e) {
    i++;
    $('#three').html("data" + i);
})
Vijay
  • 2,965
  • 1
  • 15
  • 24
  • 1
    Vijay, I agree. The Chrome Dev Tools didn't list the event either! –  Jan 29 '15 at 11:02
1

At first I've looked into a JQuery .html() function, but couldn't find anything that could cause the problem. Then I've tried to change innerHTML property without jquery (this is what I should have done first). It looks OK on Firefox 33.1 and 34.0.5, but resets selectedIndex with Chrome 40.0.2214.94, IE 10 and Opera 27.0.1689.66.

I think this proves that @Blake Plumb's comment is correct, for some browsers.

It is a repaint issue. When you change the text of the option is causes the select to repaint. In the repaint there is an issue where the prop gets reset to the default value.

loler
  • 2,594
  • 1
  • 20
  • 30
0

It's because you're setting the HTML contents of $('#three') after pre-setting the index. Therefore, if you want to keep the index of -1, rearrange your code to load in order.

<script>
    $('#three').html("moo");
    $(".drpmnu").prop('selectedIndex', -1);
</script>

An onchange event is automatically triggered when an elements value changes. Thus, the reset of the index.

RhapX
  • 1,663
  • 2
  • 10
  • 17
  • Despite that this answer solves the problem, it's more interesting why change of option's html affects select's selectedIndex – loler Jan 29 '15 at 08:02
  • 2
    If so, shouldn't `$('#three').trigger('change');` have the same effect as `$('#three').html("moo");` for selecetedIndex? – loler Jan 29 '15 at 08:20