Mostrar etiquetas de lista de datos pero enviar el valor real
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 value
atributo 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:
Firefox e IE 11:
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 42
al enviar, como lo select
harí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 value
atributo cuando se envíe el formulario?
Tenga en cuenta que datalist
no 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 select
sea una mejor opción.
Para mostrar solo el valor de texto de option
en el menú desplegable, usamos el texto interno y omitimos el value
atributo. El valor real que queremos enviar se almacena en un data-value
atributo personalizado:
Para enviar esto data-value
tenemos 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 datalist
y 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 answer
y answer-hidden
las 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 input
mensajes de correo electrónico en la misma página y uno o más datalist
mensajes 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 = inputValue
ahiddenInput.value = ""
Ejemplos de trabajo de jsFiddle: javascript simple y jQuery
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.
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.value
con value
la datalist
opción en lugar del innerText
.
Luego, el siguiente código busca un option
con eso value
, lo inserta en el campo oculto y lo reemplaza input.value
con 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 innerText
dice la opción, pero la identificación única option.value
está disponible al enviar el formulario.
Demostración jsFiddle