使用 jQuery 按字母顺序排序选项元素

我试图理解按字母顺序排序 select元素中的 option元素。理想情况下,我希望这是一个单独的函数,我可以只传递 select 元素,因为当用户单击某些按钮时需要对它进行排序。

我到处寻找这样做的好方法,但是没有找到任何对我有用的方法。

选项元素应该按字母顺序按文本排序,而不是按值排序。

这可能吗?

183421 次浏览

The jquery.selectboxes.js plugin has a sort method. You can implement the plugin, or dive into the code to see a way to sort the options.

What I'd do is:

  1. Extract the text and value of each <option> into an array of objects;
  2. Sort the array;
  3. Update the <option> elements with the array contents in order.

To do that with jQuery, you could do this:

var options = $('select.whatever option');
var arr = options.map(function(_, o) { return { t: $(o).text(), v: o.value }; }).get();
arr.sort(function(o1, o2) { return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0; });
options.each(function(i, o) {
o.value = arr[i].v;
$(o).text(arr[i].t);
});

Here is a working jsfiddle.

edit — If you want to sort such that you ignore alphabetic case, you can use the JavaScript .toUpperCase() or .toLowerCase() functions before comparing:

arr.sort(function(o1, o2) {
var t1 = o1.t.toLowerCase(), t2 = o2.t.toLowerCase();


return t1 > t2 ? 1 : t1 < t2 ? -1 : 0;
});
<select id="mSelect" >
<option value="val1" > DEF </option>
<option value="val4" > GRT </option>
<option value="val2" > ABC </option>
<option value="val3" > OPL </option>
<option value="val5" > AWS </option>
<option value="val9" > BTY </option>
</select>

.

$("#mSelect").append($("#mSelect option").remove().sort(function(a, b) {
var at = $(a).text(), bt = $(b).text();
return (at > bt)?1:((at < bt)?-1:0);
}));

Accepted answer is not the best in all cases because sometimes you want to perserve classes of options and different arguments (for example data-foo).

My solution is:

var sel = $('#select_id');
var selected = sel.val(); // cache selected value, before reordering
var opts_list = sel.find('option');
opts_list.sort(function(a, b) { return $(a).text() > $(b).text() ? 1 : -1; });
sel.html('').append(opts_list);
sel.val(selected); // set cached selected value

//For ie11 or those who get a blank options, replace html('') empty()

html:

<select id="list">
<option value="op3">option 3</option>
<option value="op1">option 1</option>
<option value="op2">option 2</option>
</select>

jQuery:

var options = $("#list option");                    // Collect options
options.detach().sort(function(a,b) {               // Detach from select, then Sort
var at = $(a).text();
var bt = $(b).text();
return (at > bt)?1:((at < bt)?-1:0);            // Tell the sort function how to order
});
options.appendTo("#list");                          // Re-attach to select

I used tracevipin's solution, which worked fantastically. I provide a slightly modified version here for anyone like me who likes to find easily readable code, and compress it after it's understood. I've also used .detach instead of .remove to preserve any bindings on the option DOM elements.

Here's my improved version of Pointy's solution:

function sortSelectOptions(selector, skip_first) {
var options = (skip_first) ? $(selector + ' option:not(:first)') : $(selector + ' option');
var arr = options.map(function(_, o) { return { t: $(o).text(), v: o.value, s: $(o).prop('selected') }; }).get();
arr.sort(function(o1, o2) {
var t1 = o1.t.toLowerCase(), t2 = o2.t.toLowerCase();
return t1 > t2 ? 1 : t1 < t2 ? -1 : 0;
});
options.each(function(i, o) {
o.value = arr[i].v;
$(o).text(arr[i].t);
if (arr[i].s) {
$(o).attr('selected', 'selected').prop('selected', true);
} else {
$(o).removeAttr('selected');
$(o).prop('selected', false);
}
});
}

The function has the skip_first parameter, which is useful when you want to keep the first option on top, e.g. when it's "choose below:".

It also keeps track of the previously selected option.

Example usage:

jQuery(document).ready(function($) {


sortSelectOptions('#select-id', true);


});

Yes you can sort the options by its text and append it back to the select box.

 function NASort(a, b) {
if (a.innerHTML == 'NA') {
return 1;
}
else if (b.innerHTML == 'NA') {
return -1;
}
return (a.innerHTML > b.innerHTML) ? 1 : -1;
};

Fiddle: https://jsfiddle.net/vaishali_ravisankar/5zfohf6v/

I know this topic is old but I think my answer can be useful for a lot of people.

Here is jQuery plugin made from Pointy's answer using ES6:

/**
* Sort values alphabetically in select
* source: http://stackoverflow.com/questions/12073270/sorting-options-elements-alphabetically-using-jquery
*/
$.fn.extend({
sortSelect() {
let options = this.find("option"),
arr = options.map(function(_, o) { return { t: $(o).text(), v: o.value }; }).get();


arr.sort((o1, o2) => { // sort select
let t1 = o1.t.toLowerCase(),
t2 = o2.t.toLowerCase();
return t1 > t2 ? 1 : t1 < t2 ? -1 : 0;
});


options.each((i, o) => {
o.value = arr[i].v;
$(o).text(arr[i].t);
});
}
});

Use is very easy

$("select").sortSelect();

Malakgeorge answer is nice an can be easily wrapped into a jQuery function:

$.fn.sortSelectByText = function(){
this.each(function(){
var selected = $(this).val();
var opts_list = $(this).find('option');
opts_list.sort(function(a, b) { return $(a).text() > $(b).text() ? 1 : -1; });
$(this).html('').append(opts_list);
$(this).val(selected);
})
return this;
}

None of the answers worked for me. For some strange reason, when looping through the options, each option returns nothing when text() is called. Instead, I was forced to retrieve the option's label via attr('label')

/**
* Sort the options of the target select list
* alphabetically by label. For some reason, when
* we call detach(), the returned options have no
* text() and instead we're forced to get the option's
* label via the 'label' attribute.
* @param select jQuery selector
*/
function sort_multi_select(select) {
var options = select.find('option');
options.detach().sort(function (a, b) {
var at = $(a).attr('label'), //label, not text()
bt = $(b).attr('label');
return at > bt ? 1 : at < bt ? -1 : 0;
});
options.appendTo(select);
}


//example
sort_multi_select($('#my_select'));

I combined parts from marxin's and kuxa's excellent answers to create a jQuery custom function that

  1. sorts the options by their text values (case-insensitive),

  2. maintains any already-selected value, and

  3. returns the original jQuery objects against which the function is executed:

    $.fn.extend({
    sortSelect() {
    return this.each(function(){
    let $this = $(this),
    original_selection = $this.val(),
    $options = $this.find('option'),
    arr = $options.map(function(_, o) { return { t: $(o).text(), v: o.value }; }).get();
    
    
    arr.sort((o1, o2) => {
    // sort select
    let t1 = o1.t.toLowerCase(),
    t2 = o2.t.toLowerCase();
    return t1 > t2 ? 1 : t1 < t2 ? -1 : 0;
    });
    
    
    $options.each((i, o) => {
    o.value = arr[i].v;
    $(o).text(arr[i].t);
    });
    
    
    $this.val(original_selection);
    })
    }
    });
    

Working example on jsFiddle is available at https://jsfiddle.net/jhfrench/64och25e/.