Mostrar etiquetas de lista de datos pero enviar el valor real

Resuelto Stephan Muller asked hace 9 años • 7 respuestas

Actualmente, el elemento HTML5 <datalist>es compatible con la mayoría de los principales navegadores (excepto Safari) y parece una forma interesante de agregar sugerencias a una entrada.

Sin embargo, parece haber algunas discrepancias entre la implementación del valueatributo y el texto interno del archivo <option>. Por ejemplo:

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

Esto lo manejan de manera diferente los diferentes navegadores:

Chrome y Ópera:
Lista de datos en Chrome/Opera

Firefox e IE 11:
Lista de datos en Firefox

Después de seleccionar uno, la entrada se completa con el valor y no con el texto interno. Solo quiero que el usuario vea el texto ("La respuesta") en el menú desplegable y en la entrada, pero pase el valor 42al enviar, como lo selectharía.

¿Cómo puedo hacer que todos los navegadores tengan la lista desplegable que muestre las etiquetas (texto interno) de los <option>correos electrónicos, pero envíen el valueatributo cuando se envíe el formulario?

Stephan Muller avatar Apr 27 '15 02:04 Stephan Muller
Aceptado

Tenga en cuenta que datalistno es lo mismo que un select. Permite a los usuarios ingresar un valor personalizado que no está en la lista y sería imposible obtener un valor alternativo para dicha entrada sin definirlo primero.

Las posibles formas de manejar la entrada del usuario son enviar el valor ingresado tal cual, enviar un valor en blanco o evitar el envío. Esta respuesta maneja solo las dos primeras opciones.

Si desea prohibir por completo la entrada del usuario, tal vez selectsea una mejor opción.


Para mostrar solo el valor de texto de optionen el menú desplegable, usamos el texto interno y omitimos el valueatributo. El valor real que queremos enviar se almacena en un data-valueatributo personalizado:

Para enviar esto data-valuetenemos que usar un <input type="hidden">. En este caso omitimos la name="answer"entrada normal y la movemos a la copia oculta.

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

De esta manera, cuando el texto en la entrada original cambia, podemos usar javascript para verificar si el texto también está presente en el archivo datalisty recuperarlo data-value. Ese valor se inserta en la entrada oculta y se envía.

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

La identificación answery answer-hiddenlas entradas normal y oculta son necesarias para que el script sepa qué entrada pertenece a qué versión oculta. De esta manera, es posible tener varios inputmensajes de correo electrónico en la misma página y uno o más datalistmensajes de correo electrónico proporcionen sugerencias.

Cualquier entrada del usuario se envía tal cual. Para enviar un valor vacío cuando la entrada del usuario no está presente en la lista de datos, cambie hiddenInput.value = inputValueahiddenInput.value = ""


Ejemplos de trabajo de jsFiddle: javascript simple y jQuery

Stephan Muller avatar Apr 26 '2015 19:04 Stephan Muller

La solución que utilizo es la siguiente:

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

Luego acceda al valor que se enviará al servidor usando JavaScript de esta manera:

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


Espero eso ayude.

Hezbullah Shah avatar May 09 '2016 12:05 Hezbullah Shah

Me doy cuenta de que esto puede ser un poco tarde, pero me topé con esto y me preguntaba cómo manejar situaciones con múltiples valores idénticos, pero claves diferentes (según el comentario de bigbearzhu).

Así que modifiqué ligeramente la respuesta de Stephan Muller:

Una lista de datos con valores no únicos:

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

Cuando el usuario selecciona una opción, el navegador la reemplaza input.valuecon valuela datalistopción en lugar del innerText.

Luego, el siguiente código busca un optioncon eso value, lo inserta en el campo oculto y lo reemplaza input.valuecon el 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;
      }

});

Como consecuencia, el usuario ve lo que innerTextdice la opción, pero la identificación única option.valueestá disponible al enviar el formulario. Demostración jsFiddle

cobbystreet avatar Apr 20 '2020 17:04 cobbystreet