Datenlistenbeschriftungen anzeigen, aber den tatsächlichen Wert angeben

90

Derzeit ist der HTML5 <datalist> Element in den meisten gängigen Browsern (außer Safari) unterstützt und scheint eine interessante Möglichkeit zu sein, einer Eingabe Vorschläge hinzuzufügen.

Es scheint jedoch einige Diskrepanzen zwischen der Implementierung des valueAttributs und dem inneren Text auf dem zu geben <option>. Beispielsweise:

<input list="answers" name="answer">
<datalist id="answers">
  <option value="42">The answer</option>
</datalist>

Dies wird von verschiedenen Browsern unterschiedlich gehandhabt:

Chrome und Opera:
Datenliste in Chrome / Opera

FireFox und IE 11:
Datalist in FireFox

Nach Auswahl eines wird die Eingabe mit dem Wert und nicht mit dem inneren Text gefüllt. Ich möchte nur, dass der Benutzer den Text ("Die Antwort") in der Dropdown-Liste und in der Eingabe sieht, aber den Wert beim Senden übergibt 42, wie zselect würde.

Wie kann ich dafür sorgen, dass alle Browser in der Dropdown-Liste die Beschriftungen (inneren Text) des <option>s anzeigen , aber das valueAttribut senden , wenn das Formular gesendet wird?

Stephan Müller
quelle
1
Ich denke, Firefox und IE11 sind hier falsch; nach den Spezifikationen One und Two scheint es , dass value=""Vorrang vor einer Zeichenfolge innerhalb der Tags übernehmen sollte, wann immer es eine ist value=""erklärt. Der Vorschlag wäre also, "die Antwort" zu Ihrem Wertattribut zu machen.
TylerH
1
@ TylerH Nein - Firefox und IE11 sind hier korrekt: Das label-Attribut liefert eine Bezeichnung für das Element. Die Beschriftung eines Optionselements ist der Wert des Beschriftungsinhaltsattributs, falls vorhanden, oder, falls nicht, der Wert des Text-IDL-Attributs des Elements. w3.org/TR/html5/forms.html#attr-option-label
easwee
1
@easwee Das heißt nur, dass das Label das sein sollte, was im Label enthalten ist, wenn es ein Label gibt, und dass der Wert das sein sollte, was im Wert enthalten ist, wenn es einen Wert gibt. Es gibt nicht an, welche Vorrang hat.
TylerH

Antworten:

107

Beachten Sie, dass dies datalistnicht dasselbe ist wie a select. Benutzer können einen benutzerdefinierten Wert eingeben, der nicht in der Liste enthalten ist, und es ist unmöglich, einen alternativen Wert für eine solche Eingabe abzurufen, ohne ihn zuerst zu definieren.

Mögliche Möglichkeiten zur Verarbeitung von Benutzereingaben bestehen darin, den eingegebenen Wert unverändert zu übermitteln, einen leeren Wert zu übermitteln oder das Übermitteln zu verhindern. Diese Antwort behandelt nur die ersten beiden Optionen.

Wenn Sie Benutzereingaben vollständig verbieten möchten, ist dies möglicherweise selectdie bessere Wahl.


Um nur den optionTextwert von in der Dropdown-Liste anzuzeigen, verwenden wir den inneren Text dafür und lassen das valueAttribut weg . Der tatsächliche Wert, den wir senden möchten, wird in einem benutzerdefinierten data-valueAttribut gespeichert :

Um dies einzureichen, müssen data-valuewir eine verwenden <input type="hidden">. In diesem Fall lassen wir name="answer"die reguläre Eingabe weg und verschieben sie in die versteckte Kopie.

<input list="suggestionList" id="answerInput">
<datalist id="suggestionList">
    <option data-value="42">The answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

Auf diese Weise können wir, wenn sich der Text in der ursprünglichen Eingabe ändert, mit Javascript prüfen, ob der Text auch in der vorhanden ist, datalistund ihn abrufendata-value . Dieser Wert wird in die versteckte Eingabe eingefügt und gesendet.

document.querySelector('input[list]').addEventListener('input', function(e) {
    var input = e.target,
        list = input.getAttribute('list'),
        options = document.querySelectorAll('#' + list + ' option'),
        hiddenInput = document.getElementById(input.getAttribute('id') + '-hidden'),
        inputValue = input.value;

    hiddenInput.value = inputValue;

    for(var i = 0; i < options.length; i++) {
        var option = options[i];

        if(option.innerText === inputValue) {
            hiddenInput.value = option.getAttribute('data-value');
            break;
        }
    }
});

Die ID answer sowie answer-hiddendie reguläre und versteckte Eingabe werden benötigt, damit das Skript weiß, welche Eingabe zu welcher versteckten Version gehört. Auf diese Weise ist es möglich, mehrere inputs mit einem oder mehreren auf derselben Seite zu habendatalist s Vorschläge liefern.

Alle Benutzereingaben werden unverändert übermittelt. Um einen leeren Wert zu senden, wenn die Benutzereingabe nicht in der Datenliste vorhanden ist, ändern Sie hiddenInput.value = inputValuezuhiddenInput.value = ""


Arbeitsbeispiele für jsFiddle: einfaches Javascript und jQuery

Stephan Müller
quelle
1
Wie würden Sie mit Optionen mit demselben inneren Text, aber unterschiedlichen Datenwerten umgehen? zB jsfiddle.net/7k3sovht/78
bigbearzhu
1
Soweit ich das beurteilen kann, gibt es keine Möglichkeit, zwischen den beiden Optionen zu unterscheiden. Da es kein Benutzerereignis zum Abhören gibt, ist es unmöglich zu wissen, welches der beiden tatsächlich ausgewählt wurde. Wir wissen nur, welcher Wert im Eingabefeld landete.
Stephan Müller
@StephanMuller tolle Antwort für jemanden, der mehr HTML5 lernt wie ich, danke! Wie würden Sie das Textfeld für die Demo nach dem Absenden löschen?
Chris22
Pure jquery document.querySelector ('input [list]'). AddEventListener ('input', Funktion (e) {var value = $ (this) .val (); var list = $ (this) .attr ('list') ); var id = $ (this) .attr ('id'); $ ('#' + list + 'option'). each (function () {if ($ (this) .val () == value) { $ ('#' + id + '- hidden'). val ($ (this) .attr ('Datenwert'));}});});
Piotr Kazuś
@StephanMuller, danke für das Teilen, sehr nützlich. Ich laufe so, wie Sie es codiert haben. Ich erhalte den Datenwert jedoch nur, wenn Sie die Rücktaste in der Eingabe verwenden, nicht, wenn Sie ein anderes Element senden oder sogar auswählen. Was kann falsch sein?
Digitai
41

Die Lösung, die ich benutze, ist die folgende:

<input list="answers" id="answer">
<datalist id="answers">
  <option data-value="42" value="The answer">
</datalist>

Greifen Sie dann mit JavaScript wie folgt auf den Wert zu, der an den Server gesendet werden soll:

var shownVal = document.getElementById("answer").value;
var value2send = document.querySelector("#answers option[value='"+shownVal+"']").dataset.value;


Ich hoffe es hilft.

Hisbollah Shah
quelle
Ich werde aus irgendeinem Grund undefiniert?
Dejell
1
Fehlerbehebung mit console.log bei jedem Schritt. Stellen Sie sicher, dass Sie denselben ID-Wert verwenden, den Sie aufrufen. Und überprüfen Sie auch Semikollons.
Hisbollah Shah
@ApurvG Dies ist die Variable, die den im Feld angezeigten Wert speichert.
Hisbollah Shah
1
Diese Lösung ist eine großartige Idee! - Ich konnte diese Lösung ziemlich einfach in wenigen Minuten implementieren. Zuerst habe ich mein inputElement mit Attribut aktualisiert data-value="1". Dann schrieb ich den folgenden Block an die Stellen, an denen der Wert if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }
erfasst
Beste Antwort für mich, einfach und klar.
Richard Aguirre
2

Mir ist klar, dass dies etwas spät sein kann, aber ich bin darauf gestoßen und habe mich gefragt, wie ich mit Situationen mit mehreren identischen Werten, aber unterschiedlichen Schlüsseln umgehen soll (gemäß Bigbearzhus Kommentar).

Also habe ich Stephan Mullers Antwort leicht modifiziert:

Ein Datalist mit nicht eindeutigen Werten:

<input list="answers" name="answer" id="answerInput">
<datalist id="answers">
  <option value="42">The answer</option>
  <option value="43">The answer</option>
  <option value="44">Another Answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

Wenn der Benutzer eine Option, der Browser ersetzt input.valuemit der valueder datalistOption statt der innerText.

Der folgende Code sucht dann nach einem optiondamit value, schiebt das in das versteckte Feld und ersetzt das input.valuedurch das innerText.

document.querySelector('#answerInput').addEventListener('input', function(e) {
    var input = e.target,   
        list = input.getAttribute('list'),
        options = document.querySelectorAll('#' + list + ' option[value="'+input.value+'"]'),
        hiddenInput = document.getElementById(input.getAttribute('id') + '-hidden');

    if (options.length > 0) {
      hiddenInput.value = input.value;
      input.value = options[0].innerText;
      }

});

Infolgedessen sieht der Benutzer, was auch immer die Option innerTextsagt, aber die eindeutige ID von option.valueist beim Senden des Formulars verfügbar. Demo jsFiddle

Cobbystreet
quelle
Schöne Ergänzung :)
Stephan Muller
1

Wenn Sie auf die Schaltfläche für die Suche klicken, können Sie sie ohne Schleife finden.
Fügen Sie der Option einfach ein Attribut mit dem Wert hinzu, den Sie benötigen (wie id), und suchen Sie danach.

$('#search_wrapper button').on('click', function(){
console.log($('option[value="'+ 
$('#autocomplete_input').val() +'"]').data('value'));
})
Gal Albalak
quelle
-11

Mit PHP habe ich einen recht einfachen Weg gefunden, dies zu tun. Leute, benutzt einfach so etwas

<input list="customers" name="customer_id" required class="form-control" placeholder="Customer Name">
            <datalist id="customers">
                <?php 
    $querySnamex = "SELECT * FROM `customer` WHERE fname!='' AND lname!='' order by customer_id ASC";
    $resultSnamex = mysqli_query($con,$querySnamex) or die(mysql_error());

                while ($row_this = mysqli_fetch_array($resultSnamex)) {
                    echo '<option data-value="'.$row_this['customer_id'].'">'.$row_this['fname'].' '.$row_this['lname'].'</option>
                    <input type="hidden" name="customer_id_real" value="'.$row_this['customer_id'].'" id="answerInput-hidden">';
                }

                 ?>
            </datalist>

Mit dem obigen Code kann das Formular die ID der ebenfalls ausgewählten Option tragen.

23r0
quelle
Das scheint ein Chaos zu sein und riecht nach SQL-Injection. Tu das nicht.
Fusseldieb
@ 23r0, einige Rückmeldungen, warum dies abgelehnt wurde; Bei dieser Frage geht es speziell um Frontend-Code. Das Einfügen von Backend-Code (wie PHP) kann unnötig und verwirrend sein. In Bezug auf den HTML-Code erwarte ich, dass Sie immer nur den letzten Wert für die customer_id_realÜbermittlung erhalten, nicht den ausgewählten Wert.
John