4

I have come across a situation where individually, these lines of code work, but in the structure I've put them in they do not. At least, not in IE 11.

If you run this code, the JS reorders the options within the select box according to alphabetical order and then selects the top item. In Chrome and Firefox this works.

In IE v11, the elements get reordered, but the top item ('five') does not become selected. Even weirder, is that if you run the final line in the IE console, it does, in fact, select the top item. So, the issue isn't that IE doesn't understand the syntax. So, what is it?

(I believe this was working as expected in prior versions of IE, but I'm not sure.)

$('#it option').sort(function(a,b){
 return ( $(a).text() > $(b).text() ) ? 1 : -1;
}).appendTo( $('#it') );

$('#it option')[0].selected = 'selected';
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="it">
 <option val="0">zero</option>
 <option val="1">one</option>
 <option val="2">two</option>
 <option val="3">three</option>
 <option val="4">four</option>
 <option val="5">five</option>
 <option val="6">six</option>
</select>

The final line $('#it option')[0].selected = 'selected'; is certainly executed in all browsers, at least if you put a console.log() before and after it you will see them output to the console. So what is it about this structure that IE doesn't like?


Some answers suggested so far, that still do not work:

These solutions still have the exact same problem of not operating as expected in IE (v11).

  1. change the line: $('#it option')[0].selected = 'selected'; to: $('#it option')[0].prop('selected',true);

  2. change the line: }).appendTo( $('#it') ); to: }).detach().appendTo( $('#it') );

Octopus
  • 8,075
  • 5
  • 46
  • 66
  • What version or versions of IE? – JasonB Jan 19 '18 at 23:29
  • @JasonB, definitely an important question, I updated to include that info. – Octopus Jan 19 '18 at 23:30
  • 1
    Does anything work on IE? Seriously now, IE is so problematic that if you search *"IE selected option not working*" you'll get tons of questions/answers, but each one due to a different issue. – Gerardo Furtado Jan 19 '18 at 23:35
  • Your sort comparator function is not valid. The comparator should return a 0 when the texts are equal. You can use the built-in `.localeCompare()` function to compare strings in a way that works for sorting. – Pointy Jan 19 '18 at 23:35
  • 1
    @Pointy, that's really not an issue, there are no two values that are equal. – Octopus Jan 19 '18 at 23:36
  • @Gerardo, in fact, this is a boiled down version of about 2000 lines of JS that otherwise work perfectly in IE and all other browsers. – Octopus Jan 19 '18 at 23:38
  • @Octopus, it seems like this is a selectedIndex issue in IE11. Check my answer below. – Jonathan Chaplin Jan 25 '18 at 15:24
  • @Octopus, since I answered your question can you award the bounty? – Jonathan Chaplin Jan 28 '18 at 14:05

3 Answers3

3

That is really weird. I can't explain it, but I found two ways to work around it:

  1. Run the 'select' code in a timeout (so it runs next tick)
  2. Use jQuery's .prop

So that would be:

$('#it option').sort(function(a,b){
  return ( $(a).text() > $(b).text() ) ? 1 : -1;
}).appendTo( $('#it') );

$('#it option:eq(0)').prop('selected', true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="it">
 <option val="0">zero</option>
 <option val="1">one</option>
 <option val="2">two</option>
 <option val="3">three</option>
 <option val="4">four</option>
 <option val="5">five</option>
 <option val="6">six</option>
</select>

Or:

$('#it option').sort(function(a,b){
  return ( $(a).text() > $(b).text() ) ? 1 : -1;
}).appendTo( $('#it') );

setTimeout(
  function() { $('#it option')[0].selected = 'selected'; }
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="it">
 <option val="0">zero</option>
 <option val="1">one</option>
 <option val="2">two</option>
 <option val="3">three</option>
 <option val="4">four</option>
 <option val="5">five</option>
 <option val="6">six</option>
</select>
Sidney
  • 4,495
  • 2
  • 18
  • 30
  • 1
    Timeout function snippet didn't work correctly for me but the .prop method version did. It's not your fault - it's Microsoft's fault. – JasonB Jan 19 '18 at 23:41
  • The prop version didnt work any better in my IE. I actually tried the timeout strategy originally in my code before coming here, but due the more complex structure of where this will actually live there are issues with me using that as a solution. – Octopus Jan 19 '18 at 23:44
  • Darn, 0 for 2 here. What versions of IE are ya'll using? – Sidney Jan 19 '18 at 23:44
  • Actually, just having tested again, `.prop` doesn't work here on Stackoverflow, but it does on Codepen. `setTimeout` works on both. So, yeah, that just about destroys any hope that I'd ever support IE. – Sidney Jan 19 '18 at 23:49
2

The short answer is that it appears to be a problem with selectedIndex. The below logs selectedIndex 6 in IE11, which in the sorted select box is the "zero" option. My code below:

$('#it option').sort(function(a,b){
    return ( $(a).text() > $(b).text() ) ? 1 : -1;
}).appendTo( $('#it') );

$('#it option')[0].selected = 'selected';
console.log($('#it')[0].selectedIndex);  //logs 6

I found two work arounds:

$('#it')[0].selectedIndex=0;
$("#it").val($("#it option")[0].text);
Jonathan Chaplin
  • 2,442
  • 1
  • 18
  • 21
  • Does that first solution really work for you? The second does for me. I want to be fairly confident that the final code I settle on will work in as many browsers as possible. – Octopus Jan 25 '18 at 17:07
  • Both work in Chrome(63), Firefox(57), and IE11. I'll create a fiddle so we can get on the same page. IE issues can be pretty irritating. – Jonathan Chaplin Jan 25 '18 at 17:20
  • ah yes, you are right I didnt reference the zero-th `select` element when I tried your first line. Both work fine. I have to wait 4 hours to award you the bounty. – Octopus Jan 25 '18 at 17:44
  • No problem, glad to help. – Jonathan Chaplin Jan 25 '18 at 17:48
  • The workaround is fine. It would be nice to know why IE does understand the `elem.selected = 'selected'`, but not right after it does a `sort().appendTo()`. – Octopus Jan 26 '18 at 17:10
  • This issue and accepted answer seems to be similar to yours. https://stackoverflow.com/questions/12942681/how-to-fix-ie-select-issue-when-dynamically-changing-options – Jonathan Chaplin Jan 26 '18 at 22:14
  • Under the hood appendTo uses appendChild which has historically caused problems in IE (https://stackoverflow.com/questions/3611615/are-add-and-appendchild-the-same-for-select-dom-objects). I think the add method is meant for adding options to select. In fact when use add it selects the right element. – Jonathan Chaplin Jan 27 '18 at 01:19
1

The issue is reordering elements. You can detach them and then put them back and the control will re-render.

$('#it option').sort(function(a,b){
 return ( $(a).text() > $(b).text() ) ? 1 : -1;
}).detach().appendTo( $('#it') );

$('#it option')[0].selected = 'selected';
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="it">
 <option val="0">zero</option>
 <option val="1">one</option>
 <option val="2">two</option>
 <option val="3">three</option>
 <option val="4">four</option>
 <option val="5">five</option>
 <option val="6">six</option>
</select>
JasonB
  • 6,243
  • 2
  • 17
  • 27