Was ist die effizienteste Methode, um die Optionen einer HTML-Auswahl nach Wert zu sortieren und dabei das aktuell ausgewählte Element beizubehalten?

80

Ich habe jQuery, bin mir aber nicht sicher, ob es integrierte Sortierhilfen gibt. Ich konnte eine 2D - Array von jedem Stück machen text, valueund selectedEigenschaften, aber ich glaube nicht , dass Javascript gebaut ist in Array.sort()richtig funktionieren wird.

Travis
quelle
4
Hinweis für sich selbst (da ich mehrmals über Google auf diese Frage zurückgekommen bin): Hier ist eine gute Lösung, die Sie geschrieben haben: gist.github.com/1072537
Travis

Antworten:

134

Extrahieren Sie Optionen in ein temporäres Array, sortieren Sie die Liste und erstellen Sie sie neu:

var my_options = $("#my_select option");
var selected = $("#my_select").val();

my_options.sort(function(a,b) {
    if (a.text > b.text) return 1;
    if (a.text < b.text) return -1;
    return 0
})

$("#my_select").empty().append( my_options );
$("#my_select").val(selected);

Die Sortierdokumentation von Mozilla (insbesondere die compareFunction) und die Sortieralgorithmus-Seite von Wikipedia sind relevant.

Wenn Sie die Groß- und Kleinschreibung nicht berücksichtigen möchten, ersetzen Sie sie textdurchtext.toLowerCase()

Die oben gezeigte Sortierfunktion veranschaulicht das Sortieren. Das genaue Sortieren nicht englischer Sprachen kann komplex sein (siehe den Unicode-Kollatierungsalgorithmus ). Die Verwendung von localeCompare in der Sortierfunktion ist eine gute Lösung, z.

my_options.sort(function(a,b) {
    return a.text.localeCompare(b.text);
});
Kennzeichen
quelle
1
3 Jahre später noch einmal auf diese Frage
eingehen
8
Beachten Sie, dass zwischen Groß- und Kleinschreibung unterschieden wird. Das heißt, alle Dinge, die mit Großbuchstaben beginnen, werden vor Dingen sortiert, die mit Kleinbuchstaben beginnen. Wenn dies unerwünscht ist, fügen Sie einfach .toUpperCase()nach jedem ein.text
TJ Ellis
10
Außerdem wird die aktuell ausgewählte Option nicht in allen Browsern unverändert beibehalten (Chrome hat sich daran erinnert, was ausgewählt wurde, Firefox und dh nicht, und das letzte Element ausgewählt, nachdem die Optionen gelesen wurden). Um dies zu beheben, speichern Sie den aktuell ausgewählten Wert vor dem Sortieren und wählen Sie ihn erneut aus. Das heißt, bevor etwas anderes getan wird var selected = $("#my_select").val(); und nachdem die sortierten Optionen angehängt wurden, stellen Sie den Wert wieder her, dh$("#my_select").val(selected);
TJ Ellis
3
cool. 'else'-Wörter können entfernt werden. Return-Ends-Funktion trotzdem.
EliSherer
@TJEllis in Bezug auf die Groß- und Kleinschreibung, diese Frage bietet noch mehr Informationen, warum man .toUpperCase()vs verwenden sollte, .toLowerCase()wenn Fälle ignoriert werden stackoverflow.com/questions/2140627/…
Adrien Be
20

Die obige Antwort von Tom wurde geringfügig geändert, sodass der Inhalt des zu sortierenden Auswahlfelds tatsächlich geändert wird, anstatt nur die sortierten Elemente zurückzugeben.

$('#your_select_box').sort_select_box();

jQuery-Funktion:

$.fn.sort_select_box = function(){
    // Get options from select box
    var my_options = $("#" + this.attr('id') + ' option');
    // sort alphabetically
    my_options.sort(function(a,b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0
    })
   //replace with sorted my_options;
   $(this).empty().append( my_options );

   // clearing any selections
   $("#"+this.attr('id')+" option").attr('selected', false);
}
JaredC
quelle
1
Diese Antwort ist ganz oben, aber nicht richtig ausgewählt
Thouliha
18

Ich habe gerade Marks Idee in eine Abfragefunktion eingewickelt

$('#your_select_box').sort_select_box();

JQuery-Funktion:

$.fn.sort_select_box = function(){
    var my_options = $("#" + this.attr('id') + ' option');
    my_options.sort(function(a,b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0
    })
   return my_options;
}
Tom Maeckelberghe
quelle
Wie kann ich dies zu meinem aktuellen Klickereignis hinzufügen? $ ('# addwire'). click (function () {return! $ ('# wireselection option: selected'). remove (). appendTo ('# wires'). sort_select_box ();}); scheint nicht zu funktionieren
mcgrailm
12

Die Lösung, die ich in meinem Kommentar zu @Juan Perez erwähnt habe

$.fn.sortOptions = function(){
    $(this).each(function(){
        var op = $(this).children("option");
        op.sort(function(a, b) {
            return a.text > b.text ? 1 : -1;
        })
        return $(this).empty().append(op);
    });
}

Verwendung:

$("select").sortOptions();

Dies kann noch verbessert werden, aber ich musste keine Schnickschnack mehr hinzufügen :)

Tom Pietrosanti
quelle
6

Nun, in IE6 scheint es nach dem [0] -Element des verschachtelten Arrays zu sortieren:

function sortSelect(selectToSort) {
    var arrOptions = [];

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

    arrOptions.sort();

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

Ich werde sehen, ob dies in anderen Browsern funktioniert ...

Edit: es funktioniert auch in Firefox, woo hoo!

Gibt es einen einfacheren Weg als diesen? Gibt es eine in Javascript oder jQuery integrierte Methode, die die Auswahl sortiert, die mir fehlt, oder ist dies der beste Weg?

Travis
quelle
8
Beachten Sie, dass diese Funktion die Optionselemente nicht sortiert . Es ändert den [Wert, Text, ausgewählt] der vorhandenen Elemente so, dass sie sortiert sind (in diesem Fall nach Wert). Dies ist für die meisten Anwendungen ausreichend. Wenn Sie jedoch andere Attribute (CSS, QuickInfos usw.) haben, reicht dieser Ansatz nicht aus.
NVRAM
6

Es gibt ein geschlossenes jQuery-Ticket für eine Sorte, die funktionieren sollte, aber nicht im Kern enthalten war.

jQuery.fn.sort = function() {
  return this.pushStack( [].sort.apply( this, arguments ), []);
};

Aus einem Google Groups-Thread referenziert , übergeben Sie einfach eine Funktion, die zum Sortieren verwendet wird

function sortSelect(selectToSort) {
    jQuery(selectToSort.options).sort(function(a,b){ 
        return a.value > b.value ? 1 : -1; 
    });
}

Ich hoffe es hilft!

bdukes
quelle
1
Einige Probleme mit der sortSelect-Funktion: Dies berücksichtigt nicht gleiche Optionen. Sortiert nach Wert und nicht nach Text. jQuery-Objekte haben keine Eigenschaft mit dem Namen "options". Hat keine Auswirkung, da Sie die Optionen an ein neues Auswahlelement anhängen müssen.
Simon
4

Dies ist eine bessere Lösung. Deklarieren Sie eine globale Funktion für JQuery

$.fn.sortSelect = function() {
    var op = this.children("option");
    op.sort(function(a, b) {
        return a.text > b.text ? 1 : -1;
    })
    return this.empty().append(op);
}

Und rufen Sie die Funktion aus dem Code auf.

$("#my_select").sortSelect();
Juan Perez
quelle
1
Ich habe eine Variation davon verwendet und den inneren Teil in $ (this) .each () eingeschlossen, damit ich ihm einen Selektor übergeben kann, der mehrere gleichzeitig behandelt.
Tom Pietrosanti
1
Außerdem müssen Sie $(this)statt nurthis
Tom Pietrosanti
2

Array.sort()Standardmäßig wird jedes Element in eine Zeichenfolge konvertiert und diese Werte verglichen. Also ["value", "text", "selected"]wird sortiert als "value, text, selected". Was wahrscheinlich die meiste Zeit gut funktionieren wird.

Wenn Sie nur nach Wert sortieren oder Wert als Zahl interpretieren möchten, können Sie eine Vergleichsfunktion an sort () übergeben:

arrOptions.sort(function(a,b) { return new Number(a[0]) - new Number(b[0]); });
Shog9
quelle
1

Denken Sie daran: Wenn Sie die Kontextauswahl verwenden möchten, funktioniert die Verkettung der ID nicht

$.fn.sort_select_box = function(){
    var my_options = $("option", $(this));
    my_options.sort(function(a,b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0
    });
    $(this).empty().append(my_options);
}

// Usando:
$("select#ProdutoFornecedorId", $($context)).sort_select_box();
João
quelle
1

Ein bisschen spät, aber für das, was es wert ist, habe ich eine komplexere Funktion implementiert, die Sie generisch einschließen können. Es gibt einige Optionen für eine abwechslungsreiche Ausgabe. Es kann auch auf <OPTGROUP>Tags basierend auf ihrer Bezeichnung zurückgreifen .

$.fn.sortSelect = function(options){

    const OPTIONS_DEFAULT = {
        recursive:      true,   // Recurse into <optgroup>
        reverse:        false,  // Reverse order
        useValues:      false,  // Use values instead of text for <option> (<optgruop> is always label based)
        blankFirst:     true,   // Force placeholder <option> with empty value first, ignores reverse
    }

    if (typeof options != "object" || null === options) {
        options = OPTIONS_DEFAULT;
    }

    var sortOptions = function($root, $node, options){

        if ($node.length != 1) {
            return false;
        }

        if ($node[0].tagName != "SELECT" && $node[0].tagName != "OPTGROUP") {
            return false;
        }

        if (options.recursive) {
            $node.children('optgroup').each(function(k, v){
                return sortOptions($root, $(v), options);
            });
        }

        var $options        = $node.children('option, optgroup');
        var $optionsSorted  = $options.sort(function(a, b){

            if (options.blankFirst) {
                if (a.tagName == "OPTION" && a.value == "") {
                    return -1;
                }

                if (b.tagName == "OPTION" && b.value == "") {
                    return 1;
                }
            }

            var textA = (a.tagName == "OPTION" ? (options.useValues ? a.value : a.text) : a.label);
            var textB = (b.tagName == "OPTION" ? (options.useValues ? a.value : b.text) : b.label);

            if (textA > textB) {
                return options.reverse ? -1 : 1;
            }

            if (textA < textB) {
                return options.reverse ? 1 : -1;
            }

            return 0;

        });

        $options.remove();
        $optionsSorted.appendTo($node);

        return true;

    };

    var selected = $(this).val();
    var sorted = sortOptions($(this), $(this), {...OPTIONS_DEFAULT, ...options});
    $(this).val(selected);

    return sorted;

};

Sie können die sortSelect()Funktion dann für jedes <SELECT>Tag oder nur für ein einzelnes Tag aufrufen , <OPTGROUP>um nur die Optionen einer Gruppe zu sortieren.

Beispiel:

$('select').sortSelect();

Umgekehrte Reihenfolge mit der Option "Umkehren":

$('select').sortSelect({
    reverse: true
});

Sie können dies automatisch auf alle Auswahlen anwenden, möglicherweise nur, wenn sie eine wichtige Klasse (z. B. "js-sort") enthalten:

$('select.js-sort').each(function(k, v){
    $(v).sortSelect();
});
Adambean
quelle