1

I have an unordered (dynamic generated via jsp <c:out>-tags) list of options in a <select>-tag. After the tag has been rendered, I reorder it with a simple JavaScript function.

If I use the onClick- event handler of the <select>-element, I'll get / see the ordered list on the webpage. If I append the function to my onLoaded-event handler, the function will be called and the debugger shows me the correct values, but the resulting order of my option-elements is not sorted.

If i add the method call after the dom-element with a plain <script>-tag, the same behavior happens.

Limitations

  • No jQuery
  • Data source is not sortable
  • onClick-handler is not a prober solution
  • Has to work in old browsers

JavaScript Source

  function sortSelectById(elementId) {
    var list = document.getElementById(elementId);
    var options = []

    for(var i = 0; i < list.length; i++) {
      options[i] = [];
      options[i][0] = list.options[i].text;
      options[i][1] = list.options[i].value;
      options[i][2] = list.options[i].selected;
    }

    options.sort();

    for (var i = 0; i < options.length; i++) {
      list.options[i].text = options[i][0];
      list.options[i].value = options[i][1];
      list.options[i].selected = options[i][2];
    }

    return;
  }
Tobonaut
  • 2,245
  • 2
  • 26
  • 39

2 Answers2

2

The problem that you're experiencing is due to the two-dimensional array. JavaScript needs to be told exactly what to sort by.

We do this by passing in a compareFunction to Array.prototype.sort().

Here's an example:

function compareFunction(a, b) {
    if (a[0] === b[0]) {
        return 0;
    }
    else {
        return (a[0] < b[0]) ? -1 : 1;
    }
}

function sortSelectById(elementId) {
    var list = document.getElementById(elementId);
    var options = []

    for (var i = 0; i < list.length; i++) {
        options[i] = [];
        options[i][0] = list.options[i].text;
        options[i][1] = list.options[i].value;
        options[i][2] = list.options[i].selected;
    }

    options.sort(compareFunction);

    for (var i = 0; i < options.length; i++) {
        list.options[i].text = options[i][0];
        list.options[i].value = options[i][1];
        list.options[i].selected = options[i][2];
    }
    document.getElementById("select").selectedIndex = 0;
    return;
}

sortSelectById("select");
<select id="select">
    <option>Banana</option>
    <option>Apple</option>
    <option>Orange</option>
    <option>Grape</option>
</select>

The compareFunction was borrowed from this answer

Community
  • 1
  • 1
Howard Renollet
  • 4,609
  • 1
  • 24
  • 31
0

Thanks for your help. The 'issue' was quite simpel but a combination of diffrent mistakes.

  1. Do not attach events to body, attach it to the root window element
  2. IE (> 6) requires another method call to append events to a handler
  3. IE (> 6) requires a method reference and no direct methodcall with parameters

The following code works in my scenario

 /* Required by the compatibility requirement for IE8 and older */
 function sortStatus() {
  sortSelectById('elem_id') ;
  // sort other fields...
 }

if (window.addEventListener) {
  window.addEventListener('load', sortStatus, false);
}
else if (window.attachEvent) {
  window.attachEvent('onload', sortStatus);
}

Update

Thanks to @Howard Renollet! The tip with the extra comperator is quite neat and works perfectly!

Tobonaut
  • 2,245
  • 2
  • 26
  • 39