Mostra le etichette del datalist ma invia il valore effettivo


98

Attualmente l' <datalist>elemento HTML5 è supportato nella maggior parte dei browser principali (eccetto Safari) e sembra un modo interessante per aggiungere suggerimenti a un input.

Tuttavia, sembrano esserci alcune discrepanze tra l'implementazione valuedell'attributo e il testo interno in <option>. Per esempio:

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

Questo viene gestito in modo diverso da browser diversi:

Chrome e Opera:
Datalist in Chrome / Opera

FireFox e IE 11:
Datalist in FireFox

Dopo averne selezionato uno, l'input viene riempito con il valore e non con il testo interno. Voglio solo che l'utente veda il testo ("La risposta") nel menu a discesa e nell'input, ma trasmetti il ​​valore 42al momento dell'invio, come selectfarebbe.

Come posso fare in modo che tutti i browser abbiano l'elenco a discesa che mostra le etichette (testo interno) delle <option>s, ma inviare l' valueattributo quando il modulo viene inviato?


1
Penso che Firefox e IE11 abbiano torto qui; secondo le specifiche Uno e Due , sembra che value=""dovrebbe avere la precedenza su una stringa all'interno dei tag, ogni volta che è presente un file value=""dichiarato. Quindi il suggerimento sarebbe quello di rendere "la risposta" il tuo attributo di valore.
TylerH

1
@TylerH No - Firefox e IE11 sono corretti qui: l'attributo label fornisce un'etichetta per l'elemento. L'etichetta di un elemento di opzione è il valore dell'attributo del contenuto dell'etichetta, se ce n'è uno, o, in caso contrario, il valore dell'attributo IDL del testo dell'elemento. w3.org/TR/html5/forms.html#attr-option-label
easwee

1
@easwee Questo dice solo che l'etichetta dovrebbe essere ciò che è in label se c'è un'etichetta e che il valore dovrebbe essere ciò che è nel valore se c'è un valore. Non specifica quale ha la precedenza.
TylerH

Risposte:


113

Nota che datalistnon è la stessa cosa di un file select. Consente agli utenti di inserire un valore personalizzato che non è nell'elenco e sarebbe impossibile recuperare un valore alternativo per tale input senza prima definirlo.

I modi possibili per gestire l'input dell'utente sono inviare il valore immesso così com'è, inviare un valore vuoto o impedire l'invio. Questa risposta gestisce solo le prime due opzioni.

Se vuoi disabilitare completamente l'input dell'utente, forse selectsarebbe una scelta migliore.


Per mostrare solo il valore del testo optionnel menu a discesa, utilizziamo il testo interno e tralascia l' valueattributo. Il valore effettivo che vogliamo inviare è memorizzato in un data-valueattributo personalizzato :

Per inviare questo data-valuedobbiamo utilizzare un file <input type="hidden">. In questo caso tralasciamo l' name="answer"input normale e lo spostiamo nella copia nascosta.

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

In questo modo, quando il testo nell'input originale cambia, possiamo usare javascript per controllare se il testo è presente anche nel file dataliste recuperarlo data-value. Quel valore viene inserito nell'input nascosto e inviato.

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;
        }
    }
});

L'id answere answer-hiddenl'input normale e nascosto sono necessari affinché lo script sappia quale input appartiene a quale versione nascosta. In questo modo è possibile avere più messaggi inputsulla stessa pagina con uno o più messaggi datalistche forniscono suggerimenti.

Qualsiasi input dell'utente viene inviato così com'è. Per inviare un valore vuoto quando l'input dell'utente non è presente nella lista dati, passare hiddenInput.value = inputValueahiddenInput.value = ""


Esempi di jsFiddle funzionanti: javascript e jQuery semplici


2
come gestireste le opzioni con lo stesso testo interno ma valori di dati diversi? ad es. jsfiddle.net/7k3sovht/78
bigbearzhu

1
Per quanto ne so, non c'è modo di distinguere tra le due opzioni. Poiché non ci sono eventi utente da ascoltare, è impossibile sapere quale dei due hanno effettivamente selezionato; tutto quello che sappiamo è quale valore è finito nel campo di input.
Stephan Muller

@StephanMuller ottima risposta per qualcuno che sta imparando di più HTML5 come me, grazie! Come cancelleresti la casella di testo per la demo dopo l'invio?
Chris22

Pure jquery document.querySelector ('input [list]'). AddEventListener ('input', function (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 ('data-value'));}});});
Piotr Kazuś

@StephanMuller grazie per la condivisione, molto utile, sto eseguendo come hai codificato, tuttavia ottengo il valore dati solo quando uso backspace nell'input, non quando invio o addirittura selezioni un elemento diverso, cosa può essere sbagliato?
digitai

47

La soluzione che utilizzo è la seguente:

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

Quindi accedi al valore da inviare al server utilizzando JavaScript in questo modo:

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


Spero che sia d'aiuto.


Sto diventando indefinito per qualsiasi motivo?
Dejell

1
Risoluzione dei problemi con console.log ad ogni passaggio. Assicurati di utilizzare lo stesso valore ID che stai chiamando. E controlla anche i semicolloni.
Hezbullah Shah

1
questa soluzione è un'ottima idea! - Sono stato in grado, piuttosto semplicemente, di implementare questa soluzione in pochi minuti. prima ho aggiornato il mio inputelemento con l'attributo data-value="1". Quindi ho scritto il seguente blocco nei punti in cui il valore veniva afferrato e utilizzato:if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }
WEBjuju

1
Ma cosa succede se hai due didascalie uguali con alcuni valori di dati diversi
Richard Aguirre

1
Grazie Hezbullah Shah hai davvero risparmiato così tante ore
ABODE

5

Mi rendo conto che potrebbe essere un po 'tardi, ma mi sono imbattuto in questo e mi chiedevo come gestire situazioni con più valori identici, ma chiavi diverse (come da commento di bigbearzhu).

Quindi ho modificato leggermente la risposta di Stephan Muller:

Un datalist con valori non univoci:

<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">

Quando l'utente seleziona un'opzione, il browser la sostituisce input.valuecon valuel' datalistopzione dell'opzione invece di innerText.

Il codice seguente verifica quindi la presenza di un optioncon quello value, lo inserisce nel campo nascosto e lo sostituisce input.valuecon 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;
      }

});

Di conseguenza l'utente vede qualunque cosa dica l'opzione innerText, ma l'id univoco di option.valueè disponibile al momento dell'invio del modulo. Demo jsFiddle


Bella aggiunta :)
Stephan Muller

1

Quando si fa clic sul pulsante per la ricerca, è possibile trovarlo senza loop.
Basta aggiungere all'opzione un attributo con il valore che ti serve (come id) e cercarlo in modo specifico.

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

-11

Utilizzando PHP ho trovato un modo abbastanza semplice per farlo. Ragazzi, usate qualcosa del genere

<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>

Il codice sopra consente al modulo di portare anche l'id dell'opzione selezionata.


Sembra un casino e odora di iniezione SQL. Non farlo.
Fusseldieb

@ 23r0, alcuni commenti sul motivo per cui questo potrebbe essere stato rifiutato; questa domanda riguarda specificamente il codice frontend. Includere il codice di backend (come PHP) potrebbe non essere necessario e creare confusione. Per quanto riguarda l'HTML, mi aspetto che riceverai solo l'ultimo valore per l' customer_id_realinvio, non il valore selezionato.
Giovanni
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.