Javascript to sort contents of select element

is there a quick way to sort the items of a select element? Or I have to resort to writing javascript?

Please any ideas.

<select size="4" name="lstALL" multiple="multiple" id="lstALL" tabindex="12" style="font-size:XX-Small;height:95%;width:100%;">
<option value="0"> XXX</option>
<option value="1203">ABC</option>
<option value="1013">MMM</option>
</select>

Answers:

Answer

This will do the trick. Just pass it your select element a la: document.getElementById('lstALL') when you need your list sorted.

function sortSelect(selElem) {
    var tmpAry = new Array();
    for (var i=0;i<selElem.options.length;i++) {
        tmpAry[i] = new Array();
        tmpAry[i][0] = selElem.options[i].text;
        tmpAry[i][1] = selElem.options[i].value;
    }
    tmpAry.sort();
    while (selElem.options.length > 0) {
        selElem.options[0] = null;
    }
    for (var i=0;i<tmpAry.length;i++) {
        var op = new Option(tmpAry[i][0], tmpAry[i][1]);
        selElem.options[i] = op;
    }
    return;
}
Answer

Working with the answers provided by Marco Lazzeri and Terre Porter (vote them up if this answer is useful), I came up with a slightly different solution that preserves the selected value (probably doesn't preserve event handlers or attached data, though) using jQuery.

// save the selected value for sorting
var v = jQuery("#id").val();

// sort the options and select the value that was saved
j$("#id")
    .html(j$("#id option").sort(function(a,b){
        return a.text == b.text ? 0 : a.text < b.text ? -1 : 1;}))
    .val(v);
Answer

Another option:

function sortSelect(elem) {
    var tmpAry = [];
    // Retain selected value before sorting
    var selectedValue = elem[elem.selectedIndex].value;
    // Grab all existing entries
    for (var i=0;i<elem.options.length;i++) tmpAry.push(elem.options[i]);
    // Sort array by text attribute
    tmpAry.sort(function(a,b){ return (a.text < b.text)?-1:1; });
    // Wipe out existing elements
    while (elem.options.length > 0) elem.options[0] = null;
    // Restore sorted elements
    var newSelectedIndex = 0;
    for (var i=0;i<tmpAry.length;i++) {
        elem.options[i] = tmpAry[i];
        if(elem.options[i].value == selectedValue) newSelectedIndex = i;
    }
    elem.selectedIndex = newSelectedIndex; // Set new selected index after sorting
    return;
}
Answer

This is a a recompilation of my 3 favorite answers on this board:

  • jOk's best and simplest answer.
  • Terry Porter's easy jQuery method.
  • SmokeyPHP's configurable function.

The results are an easy to use, and easily configurable function.

First argument can be a select object, the ID of a select object, or an array with at least 2 dimensions.

Second argument is optional. Defaults to sorting by option text, index 0. Can be passed any other index so sort on that. Can be passed 1, or the text "value", to sort by value.

Sort by text examples (all would sort by text):

 sortSelect('select_object_id');
 sortSelect('select_object_id', 0);
 sortSelect(selectObject);
 sortSelect(selectObject, 0);

Sort by value (all would sort by value):

 sortSelect('select_object_id', 'value');
 sortSelect('select_object_id', 1);
 sortSelect(selectObject, 1);

Sort any array by another index:

var myArray = [
  ['ignored0', 'ignored1', 'Z-sortme2'],
  ['ignored0', 'ignored1', 'A-sortme2'],
  ['ignored0', 'ignored1', 'C-sortme2'],
];

sortSelect(myArray,2);

This last one will sort the array by index-2, the sortme's.

Main sort function

function sortSelect(selElem, sortVal) {

    // Checks for an object or string. Uses string as ID. 
    switch(typeof selElem) {
        case "string":
            selElem = document.getElementById(selElem);
            break;
        case "object":
            if(selElem==null) return false;
            break;
        default:
            return false;
    }

    // Builds the options list.
    var tmpAry = new Array();
    for (var i=0;i<selElem.options.length;i++) {
        tmpAry[i] = new Array();
        tmpAry[i][0] = selElem.options[i].text;
        tmpAry[i][1] = selElem.options[i].value;
    }

    // allows sortVal to be optional, defaults to text.
    switch(sortVal) {
        case "value": // sort by value
            sortVal = 1;
            break;
        default: // sort by text
            sortVal = 0;
    }
    tmpAry.sort(function(a, b) {
        return a[sortVal] == b[sortVal] ? 0 : a[sortVal] < b[sortVal] ? -1 : 1;
    });

    // removes all options from the select.
    while (selElem.options.length > 0) {
        selElem.options[0] = null;
    }

    // recreates all options with the new order.
    for (var i=0;i<tmpAry.length;i++) {
        var op = new Option(tmpAry[i][0], tmpAry[i][1]);
        selElem.options[i] = op;
    }

    return true;
}
Answer

Yes DOK has the right answer ... either pre-sort the results before you write the HTML (assuming it's dynamic and you are responsible for the output), or you write javascript.

The Javascript Sort method will be your friend here. Simply pull the values out of the select list, then sort it, and put them back :-)

Answer

Í think this is a better option (I use @Matty's code and improved!):

function sortSelect(selElem, bCase) {
                var tmpAry = new Array();
                bCase = (bCase ? true : false);
                for (var i=0;i<selElem.options.length;i++) {
                        tmpAry[i] = new Array();
                        tmpAry[i][0] = selElem.options[i].text;
                        tmpAry[i][1] = selElem.options[i].value;
                }
                if (bCase)
                    tmpAry.sort(function (a, b) {
                        var ret = 0;
                        var iPos = 0;
                        while (ret == 0 && iPos < a.length && iPos < b.length)
                        {
                            ret = (String(a).toLowerCase().charCodeAt(iPos) - String(b).toLowerCase().charCodeAt(iPos));
                            iPos ++;
                        }
                        if (ret == 0)
                        {
                            ret = (String(a).length - String(b).length);
                        }
                        return ret;
                        });
                else
                    tmpAry.sort();
                while (selElem.options.length > 0) {
                    selElem.options[0] = null;
                }
                for (var i=0;i<tmpAry.length;i++) {
                        var op = new Option(tmpAry[i][0], tmpAry[i][1]);
                        selElem.options[i] = op;
                }
                return;
        }
Answer

I used this bubble sort because I wasnt able to order them by the .value in the options array and it was a number. This way I got them properly ordered. I hope it's useful to you too.

function sortSelect(selElem) {
  for (var i=0; i<(selElem.options.length-1); i++)
      for (var j=i+1; j<selElem.options.length; j++)
          if (parseInt(selElem.options[j].value) < parseInt(selElem.options[i].value)) {
              var dummy = new Option(selElem.options[i].text, selElem.options[i].value);
              selElem.options[i] = new Option(selElem.options[j].text, selElem.options[j].value);
              selElem.options[j] = dummy;
          }
}
Answer

I've quickly thrown together one that allows choice of direction ("asc" or "desc"), whether the comparison should be done on the option value (true or false) and whether or not leading and trailing whitespace should be trimmed before comparison (boolean).

The benefit of this method, is that the selected choice is kept, and all other special properties/triggers should also be kept.

function sortOpts(select,dir,value,trim)
{
    value = typeof value == 'boolean' ? value : false;
    dir = ['asc','desc'].indexOf(dir) > -1 ? dir : 'asc';
    trim = typeof trim == 'boolean' ? trim : true;
    if(!select) return false;
    var opts = select.getElementsByTagName('option');

    var options = [];
    for(var i in opts)
    {
        if(parseInt(i)==i)
        {
            if(trim)
            {
                opts[i].innerHTML = opts[i].innerHTML.replace(/^\s*(.*)\s*$/,'$1');
                opts[i].value = opts[i].value.replace(/^\s*(.*)\s*$/,'$1');
            }
            options.push(opts[i]);
        }
    }
    options.sort(value ? sortOpts.sortVals : sortOpts.sortText);
    if(dir == 'desc') options.reverse();
    options.reverse();
    for(var i in options)
    {
        select.insertBefore(options[i],select.getElementsByTagName('option')[0]);
    }
}
sortOpts.sortText = function(a,b) {
    return a.innerHTML > b.innerHTML ? 1 : -1;
}
sortOpts.sortVals = function(a,b) {
    return a.value > b.value ? 1 : -1;
}
Answer

Inspired by @Terre Porter's answer, I think this one is very simple to implement (using jQuery)

var $options = jQuery("#my-dropdownlist-id > option"); 
// or jQuery("#my-dropdownlist-id").find("option")

$options.sort(function(a, b) {
    return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
})

But, for Alpha/Numeric dropdown lists :

Inspired by : https://stackoverflow.com/a/4340339/1598891

var $options = jQuery(dropDownList).find("option");

var reAlpha = /[^a-zA-Z]/g;
var reNumeric = /[^0-9]/g;
$options.sort(function AlphaNumericSort($a,$b) {
    var a = $a.text;
    var b = $b.text;
    var aAlpha = a.replace(reAlpha, "");
    var bAlpha = b.replace(reAlpha, "");
    if(aAlpha === bAlpha) {
        var aNumeric = parseInt(a.replace(reNumeric, ""), 10);
        var bNumeric = parseInt(b.replace(reNumeric, ""), 10);
        return aNumeric === bNumeric ? 0 : aNumeric > bNumeric ? 1 : -1;
    } else {
        return aAlpha > bAlpha ? 1 : -1;
    }
})

Hope it will help

First example Second example

Answer

Not quite as pretty as the JQuery example by Marco but with prototype (i may be missing a more elegant solution) it would be:

function sort_select(select) {
  var options = $A(select.options).sortBy(function(o) { return o.innerHTML });
  select.innerHTML = "";
  options.each(function(o) { select.insert(o); } );
}

And then just pass it a select element:

sort_select( $('category-select') );
Answer

Just another way to do it with jQuery:

// sorting;
var selectElm = $("select"),
    selectSorted = selectElm.find("option").toArray().sort(function (a, b) {
        return (a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase()) ? 1 : -1;
    });
selectElm.empty();
$.each(selectSorted, function (key, value) {
    selectElm.append(value);
});
Answer

Try this...hopefully it will offer you a solution:

function sortlist_name()
{

    var lb = document.getElementById('mylist');
    arrTexts = new Array();
    newTexts = new Array();
    txt = new Array();
    newArray =new Array();
    for(i=0; i<lb.length; i++)
    {
      arrTexts[i] = lb.options[i].text;
    }
    for(i=0;i<arrTexts.length; i++)
    {
        str = arrTexts[i].split(" -> ");
        newTexts[i] = str[1]+' -> '+str[0];
    }
    newTexts.sort();
    for(i=0;i<newTexts.length; i++)
    {
        txt = newTexts[i].split(' -> ');
        newArray[i] = txt[1]+' -> '+txt[0];
    }
    for(i=0; i<lb.length; i++)
    {
        lb.options[i].text = newArray[i];
        lb.options[i].value = newArray[i];
    }
}
/***********revrse by name******/
function sortreverse_name()
{

    var lb = document.getElementById('mylist');
    arrTexts = new Array();
    newTexts = new Array();
    txt = new Array();
    newArray =new Array();
    for(i=0; i<lb.length; i++)
    {
      arrTexts[i] = lb.options[i].text;
    }
    for(i=0;i<arrTexts.length; i++)
    {
        str = arrTexts[i].split(" -> ");
        newTexts[i] = str[1]+' -> '+str[0];
    }
    newTexts.reverse();
    for(i=0;i<newTexts.length; i++)
    {
        txt = newTexts[i].split(' -> ');
        newArray[i] = txt[1]+' -> '+txt[0];
    }
    for(i=0; i<lb.length; i++)
    {
        lb.options[i].text = newArray[i];
        lb.options[i].value = newArray[i];
    }
}

function sortlist_id() {
var lb = document.getElementById('mylist');
arrTexts = new Array();

for(i=0; i<lb.length; i++)  {
  arrTexts[i] = lb.options[i].text;
}

arrTexts.sort();

for(i=0; i<lb.length; i++)  {
  lb.options[i].text = arrTexts[i];
  lb.options[i].value = arrTexts[i];
}
}

/***********revrse by id******/
function sortreverse_id() {
var lb = document.getElementById('mylist');
arrTexts = new Array();

for(i=0; i<lb.length; i++)  {
  arrTexts[i] = lb.options[i].text;
}

arrTexts.reverse();

for(i=0; i<lb.length; i++)  {
  lb.options[i].text = arrTexts[i];
  lb.options[i].value = arrTexts[i];
}
}
</script>



  ID<a href="javascript:sortlist_id()"> &#x25B2;  </a> <a href="javascript:sortreverse_id()">&#x25BC;</a> |  Name<a href="javascript:sortlist_name()"> &#x25B2;  </a> <a href="javascript:sortreverse_name()">&#x25BC;</a><br/>

<select name=mylist id=mylist size=8 style='width:150px'>

<option value="bill">4 -> Bill</option>
<option value="carl">5 -> Carl</option>
<option value="Anton">1 -> Anton</option>
<option value="mike">2 -> Mike</option>
<option value="peter">3 -> Peter</option>
</select>
<br>
Answer

Vanilla JS es6 Localization Options Sorting Example

const optionNodes = Array.from(selectNode.children);
const comparator = new Intl.Collator(lang.slice(0, 2)).compare;

optionNodes.sort((a, b) => comparator(a.textContent, b.textContent));
optionNodes.forEach((option) => selectNode.appendChild(option));

My use case was to localize a country select dropdown with locale aware sorting. This was used on 250 + options and was very performant ~10ms on my machine.

Answer

This solution worked very nicely for me using jquery, thought I'd cross reference it here as I found this page before the other one. Someone else might do the same.

$("#id").html($("#id option").sort(function (a, b) {
    return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
}))

from Sorting dropdown list using Javascript

Answer

From the W3C FAQ:

Although many programming languages have devices like drop-down boxes that have the capability of sorting a list of items before displaying them as part of their functionality, the HTML <select> function has no such capabilities. It lists the <options> in the order received.

You'd have to sort them by hand for a static HTML document, or resort to Javascript or some other programmatic sort for a dynamic document.

Answer

I had the same problem. Here's the jQuery solution I came up with:

  var options = jQuery.makeArray(optionElements).
                       sort(function(a,b) {
                         return (a.innerHTML > b.innerHTML) ? 1 : -1;
                       });
  selectElement.html(options);
Answer

I had a similar problem, except I wanted the selected items to show up on top, and I didn't want to clear which items were selected (multi-select list). Mine is jQuery based...

function SortMultiSelect_SelectedTop(slt) {
    var options =
        $(slt).find("option").sort(function (a, b) {
            if (a.selected && !b.selected) return -1;
            if (!a.selected && b.selected) return 1;
            if (a.text < b.text) return -1;
            if (a.text > b.text) return 1;
            return 0;
        });
    $(slt).empty().append(options).scrollTop(0);
}

Without selected on top, it would look like this.

function SortMultiSelect(slt) {
    var options =
        $(slt).find("option").sort(function (a, b) {
            if (a.text < b.text) return -1;
            if (a.text > b.text) return 1;
            return 0;
        });
    $(slt).empty().append(options).scrollTop(0);
}
Answer
function call() {
    var x = document.getElementById("mySelect");
    var optionVal = new Array();

    for (i = 0; i < x.length; i++) {
        optionVal.push(x.options[i].text);
    }

    for (i = x.length; i >= 0; i--) {
        x.remove(i);
    }

    optionVal.sort();

    for (var i = 0; i < optionVal.length; i++) {
        var opt = optionVal[i];
        var el = document.createElement("option");
        el.textContent = opt;
        el.value = opt;
        x.appendChild(el);
    }
}

The idea is to pullout all the elements of the selectbox into an array , delete the selectbox values to avoid overriding, sort the array and then push back the sorted array into the select box

Answer
function sortItems(c) {
var options = c.options;
Array.prototype.sort.call(options, function (a, b) {
    var aText = a.text.toLowerCase();
    var bText = b.text.toLowerCase();
    if (aText < bText) {
        return -1;
    } else if (aText > bText) {
        return 1;
    } else {
        return 0;
    }
});
}

sortItems(document.getElementById('lstALL'));
Answer

For those who are looking to sort whether or not there are optgroup :

/**
 * Sorting options 
 * and optgroups
 * 
 * @param selElem select element
 * @param optionBeforeGroup ?bool if null ignores, if true option appear before group else option appear after group
 */
function sortSelect(selElem, optionBeforeGroup = null) {
    let initialValue = selElem.tagName === "SELECT" ? selElem.value : null; 
    let allChildrens = Array.prototype.slice.call(selElem.childNodes);
    let childrens = [];

    for (let i = 0; i < allChildrens.length; i++) {
        if (allChildrens[i].parentNode === selElem && ["OPTGROUP", "OPTION"].includes(allChildrens[i].tagName||"")) {
            if (allChildrens[i].tagName == "OPTGROUP") {
                sortSelect(allChildrens[i]);
            }
            childrens.push(allChildrens[i]);
        }
    }

    childrens.sort(function(a, b){
        let x = a.tagName == "OPTGROUP" ? a.getAttribute("label") : a.innerHTML;
        let y = b.tagName == "OPTGROUP" ? b.getAttribute("label") : b.innerHTML;
        x = typeof x === "undefined" || x === null ? "" : (x+"");
        y = typeof y === "undefined" || y === null ? "" : (y+"");

        if (optionBeforeGroup === null) {
            if (x.toLowerCase().trim() < y.toLowerCase().trim()) {return -1;}
            if (x.toLowerCase().trim() > y.toLowerCase().trim()) {return 1;}
        } else if (optionBeforeGroup === true) {
            if ((a.tagName == "OPTION" && b.tagName == "OPTGROUP") || x.toLowerCase().trim() < y.toLowerCase().trim()) {return -1;}
            if ((a.tagName == "OPTGROUP" && b.tagName == "OPTION") || x.toLowerCase().trim() > y.toLowerCase().trim()) {return 1;}
        } else if (optionBeforeGroup === false) {
            if ((a.tagName == "OPTGROUP" && b.tagName == "OPTION") || x.toLowerCase().trim() < y.toLowerCase().trim()) {return -1;}
            if ((a.tagName == "OPTION" && b.tagName == "OPTGROUP") || x.toLowerCase().trim() > y.toLowerCase().trim()) {return 1;}
        }
        return 0;
    });

    if (optionBeforeGroup !== null) {
        childrens.sort(function(a, b){
            if (optionBeforeGroup === true) {
                if (a.tagName == "OPTION" && b.tagName == "OPTGROUP") {return -1;}
                if (a.tagName == "OPTGROUP" && b.tagName == "OPTION") {return 1;}
            } else {
                if (a.tagName == "OPTGROUP" && b.tagName == "OPTION") {return -1;}
                if (a.tagName == "OPTION" && b.tagName == "OPTGROUP") {return 1;}
            }
            return 0;
        });
    }

    selElem.innerHTML = "";
    for (let i = 0; i < childrens.length; i++) {
        selElem.appendChild(childrens[i]);
    }

    if (selElem.tagName === "SELECT") {
        selElem.value = initialValue;
    }
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.