Cómo manejar flotantes y separadores decimales con el número de tipo de entrada html5

128

Estoy construyendo una aplicación web que es principalmente para navegadores móviles. Estoy usando campos de entrada con tipo de número, por lo que (la mayoría) los navegadores móviles invocan solo el teclado numérico para una mejor experiencia del usuario. Esta aplicación web se usa principalmente en regiones donde el separador decimal es una coma, no un punto, por lo que necesito manejar ambos separadores decimales.

¿Cómo cubrir todo este desastre con punto y coma?

Mis hallazgos:

Chrome de escritorio

  • Tipo de entrada = número
  • El usuario ingresa "4,55" al campo de entrada
  • $("#my_input").val(); devuelve "455"
  • No puedo obtener el valor correcto de la entrada

Desktop Firefox

  • Tipo de entrada = número
  • El usuario ingresa "4,55" al campo de entrada
  • $("#my_input").val(); devuelve "4,55"
  • Está bien, puedo reemplazar la coma con un punto y obtener el flotador correcto

Navegador de Android

  • Tipo de entrada = número
  • El usuario ingresa "4,55" al campo de entrada
  • Cuando la entrada pierde el foco, el valor se trunca a "4"
  • Confuso para el usuario

Windows Phone 8

  • Tipo de entrada = número
  • El usuario ingresa "4,55" al campo de entrada
  • $("#my_input").val(); devuelve "4,55"
  • Está bien, puedo reemplazar la coma con un punto y obtener el flotador correcto

¿Cuáles son las "mejores prácticas" en este tipo de situaciones en las que el usuario puede usar coma o punto como separador decimal y quiero mantener el tipo de entrada html como número, para proporcionar una mejor experiencia de usuario?

¿Puedo convertir una coma en punto "sobre la marcha", vinculando eventos clave, ¿funciona con entradas numéricas?

EDITAR

Actualmente no tengo ninguna solución, cómo obtener un valor flotante (como cadena o número) de la entrada cuyo tipo se establece en número. Si el usuario final ingresa "4,55", Chrome devuelve siempre "455", Firefox devuelve "4,55", lo cual está bien.

También es bastante molesto que en Android (probado el emulador 4.2), cuando ingreso "4,55" para ingresar el campo y cambio el foco a otro lugar, el número ingresado se trunca a "4".

devha
fuente
Supongo que la causa raíz de algunos de sus problemas es que los navegadores están configurados en un entorno local de EE. UU. Que utiliza el punto como separador decimal. Parece que Chrome y Android se confunden con esto de diferentes maneras: Chrome trata la coma como un separador de dígitos, luego convierte la entrada en un número, luego la convierte nuevamente en una cadena .val()y Android hace algo extraño. ¿Puede verificar si se comportan igual cuando configura el idioma del sistema en algo apropiado?
millimoose
1
Nvm publicó esto como respuesta
kjetilh
Ver también aquí: stackoverflow.com/a/24423879/196210
Anterior
La situación es aún peor de lo que representaba: obtiene un punto decimal o una coma en el teclado numérico WP dependiendo del idioma en el que eligió el teclado para trabajar. Tampoco hay forma de averiguar cuál era la configuración regional de entrada (no necesariamente el idioma preferido del navegador) ... Así que lo mejor que puedo encontrar (y lo que es lo suficientemente bueno para mí) es: var number = $(...).get(0).valueAsNumber; if (isNaN(number)) number = parseFloat($(...).val().replace(',', '.'); Pero esa solución solo funciona si el el número que se ha introducido solo contiene 1 coma y ningún punto extra ...
bert bruynooghe

Respuestas:

107

Creo que lo que falta en las respuestas anteriores es la necesidad de especificar un valor diferente para el stepatributo, que tiene un valor predeterminado de 1. Si desea que el algoritmo de validación de entrada permita valores de punto flotante, especifique un paso en consecuencia.

Por ejemplo, quería cantidades en dólares, así que especifiqué un paso como este:

 <input type="number" name="price"
           pattern="[0-9]+([\.,][0-9]+)?" step="0.01"
            title="This should be a number with up to 2 decimal places.">

No hay nada de malo en usar jQuery para recuperar el valor, pero le resultará útil usar la API DOM directamente para obtener la validity.validpropiedad de los elementos .

Tuve un problema similar con el punto decimal, pero la razón por la que me di cuenta de que había un problema fue por el estilo que Twitter Bootstrap agrega a una entrada de número con un valor no válido.

Aquí hay un violín que demuestra que la adición del stepatributo lo hace funcionar y también prueba si el valor actual es válido:

TL; DR: establece el stepatributo a un valor de punto flotante, ya que su valor predeterminado es 1.

NOTA : La coma no es válida para mí, pero sospecho que si configuro la configuración de idioma / región del sistema operativo en algún lugar que use una coma como separador decimal, funcionaría. * nota en nota *: ese no era el caso para la configuración del idioma / teclado del sistema operativo * alemán * en Ubuntu / Gnome 14.04.

natchiketa
fuente
8
Si desea permitir arbitrariamente muchos decimales, especifique el stepatributo como en "any"lugar de, por ejemplo, "0.01"como se muestra aquí. Vea esta versión modificada del violín de nathciketa para una demostración.
Mark Amery
44
También me encontré con problemas con comas que no se validaban, aunque estaba ingresando "1,234.56" <input type="number" step="any">. No he podido encontrar una manera de desactivar la validación HTML5. Puedo desactivar o personalizar el mensaje de error, pero recuperar el valor de la entrada siempre es una trampa. ¿Algunas ideas?
Nick G.
55
This attribute applies when the value of the type attribute is text, search, tel, url, email, or password, otherwise it is ignored.Así que el patrón no sirve para nadatype="number"
Michael Laffargue
como dijo Michael, por favor cambie el typea text, de lo contrario su respuesta no tiene sentido.
phil294
23

Según w3.org, el atributo de valor de la entrada numérica se define como un número de coma flotante . La sintaxis del número de coma flotante parece aceptar solo puntos como separadores decimales.

He enumerado algunas opciones a continuación que pueden serle útiles:

1. Usando el atributo de patrón

Con el atributo de patrón , puede especificar el formato permitido con una expresión regular de manera compatible con HTML5. Aquí puede especificar que el carácter de coma está permitido y un mensaje de respuesta útil si el patrón falla.

<input type="number" pattern="[0-9]+([,\.][0-9]+)?" name="my-num"
           title="The number input must start with a number and use either comma or a dot as a decimal character."/>

Nota: la compatibilidad entre navegadores varía mucho. Puede ser completo, parcial o inexistente.

2. Validación de JavaScript

Podría intentar vincular una devolución de llamada simple, por ejemplo, al evento onchange (y / o blur ) que reemplazaría la coma o la validaría por completo.

3. Deshabilitar la validación del navegador ##

En tercer lugar, podría intentar utilizar el atributo formnovalidate en las entradas numéricas con la intención de deshabilitar la validación del navegador para ese campo por completo.

<input type="number" formnovalidate />

4. Combinación ..?

<input type="number" pattern="[0-9]+([,\.][0-9]+)?" 
           name="my-num" formnovalidate
           title="The number input must start with a number and use either comma or a dot as a decimal character."/>
kjetilh
fuente
2
input.valueAsNumber : no ayuda, ya que esto solo funciona con puntos como separador decimal y, en mi caso, el usuario final podría usar punto o coma. Novalidate de etiqueta de formulario : no se ha encontrado ningún efecto en esto.
devha
Lamentablemente, me estoy quedando sin ideas, por lo que no estoy seguro de si puede hacer que este navegador funcione sin una solución alternativa. He actualizado mi respuesta para incluir el atributo de patrón . También encontré que uno puede usar el atributo formnovalidate directamente en los campos de entrada. Sé que no te gustará, pero si todo falla y necesitas absolutamente comas, entonces input = "text" podría ser la única forma ...
kjetilh
Parece que el número de tipo de entrada genera más problemas de los que realmente mejora la experiencia del usuario. En un dispositivo móvil, sería genial si solo puedo abrir un teclado numérico para el usuario si quiero que ingresen solo números. De todos modos tengo que volver a pensar en esto, una vez más ...
devha
Debido a que también necesitamos admitir el uso de punto y coma como separador decimal, planeamos usar el patrón para la validación en el escritorio en combinación con type = "text". Luego agregaremos la detección de funciones para detectar dispositivos móviles y usaremos type = "number" cuando corresponda.
asombro
9

El uso de coma o punto para el separador decimal depende completamente del navegador. El navegador toma una decisión basada en la configuración regional del sistema operativo o navegador, o algunos navegadores toman pistas del sitio web. Hice una tabla de comparación de navegadores que muestra cómo los diferentes navegadores admiten diferentes métodos de localización. Safari es el único navegador que maneja comas y puntos de manera intercambiable.

Básicamente, usted como autor web no puede controlar esto realmente. Algunas soluciones implican el uso de dos campos de entrada con enteros. Esto permite que cada usuario ingrese los datos como espera. No es particularmente sexy, pero funcionará en todos los casos para todos los usuarios.

Aeyoun
fuente
7

Usar en valueAsNumberlugar de .val().

entrada. valueAsNumber [= value]

Devuelve un número que representa el valor del control de formulario, si corresponde; de lo contrario, devuelve nulo.
Se puede configurar, para cambiar el valor.
Lanza una excepción INVALID_STATE_ERR si el control no está basado en fecha o hora ni es numérico.

Mike Samuel
fuente
2
El problema es que quiere admitir comas como separador decimal, y usar type = "number" en la entrada siempre da un número no válido al escribir comas.
asombro
Parece que no funciona constantemente en Windows Phone; siempre vuelve NaN.
bert bruynooghe
@bertbruynooghe, ¿Qué estás asignando como valor?
Mike Samuel
No parece funcionar, ni con '9', '9,1', '9.1'. El teléfono está configurado como EE. UU., Los diseños de teclado se probaron en EE. UU., Nl-BE.
bert bruynooghe
4

usa un tipo de texto pero fuerza la apariencia del teclado numérico

<input value="12,4" type="text" inputmode="numeric" pattern="[-+]?[0-9]*[.,]?[0-9]+">

la etiqueta inputmode es la solución

David Navarro
fuente
Pero no es compatible con todos los navegadores, solo con las últimas versiones de iOS Safari, Chrome, Chromium, Opera ... caniuse.com/#feat=input-inputmode :(
pgarciacamou
Y además, no obtienes este teclado numérico ordenado en dispositivos móviles.
WoIIe
3

No he encontrado una solución perfecta, pero lo mejor que pude hacer fue usar type = "tel" y deshabilitar la validación html5 (formnovalidate):

<input name="txtTest" type="tel" value="1,200.00" formnovalidate="formnovalidate" />

Si el usuario pone una coma, saldrá con la coma en todos los navegadores modernos que probé (último FF, IE, edge, opera, chrome, safari desktop, android chrome).

El problema principal es:

  • Los usuarios móviles verán el teclado de su teléfono, que puede ser diferente del teclado numérico.
  • Peor aún, el teclado del teléfono puede no tener una tecla para una coma.

Para mi caso de uso solo tuve que:

  • Muestra el valor inicial con una coma (Firefox lo elimina para type = number)
  • No falla la validación html5 (si hay una coma)
  • Haga que el campo se lea exactamente como entrada (con una posible coma)

Si tiene un requisito similar, esto debería funcionar para usted.

Nota: no me gustó el soporte del atributo de patrón. El formnovalidate parece funcionar mucho mejor.

Bolo
fuente
1

Cuando lo llamas $("#my_input").val();vuelve como variable de cadena. Así que usa parseFloaty parseIntpara convertir. Cuando usa parseFloatsu computadora de escritorio o teléfono, SÍ MISMO comprende el significado de variable.

Y además, puede convertir un flotador en una cadena mediante el toFixedcual tiene un argumento el recuento de dígitos como se muestra a continuación:

var i = 0.011;
var ss = i.toFixed(2); //It returns 0.01

fuente
No funciona. Pruebe parseFloat ("1,5") en IE11. Devoluciones 1. El idioma es alemán tanto para SO como para IE.
T3rm1
1

Aparentemente, los navegadores todavía tienen problemas (aunque Chrome y Firefox Nightly funcionan bien). Tengo un enfoque hacky para las personas que realmente tienen que usar un campo numérico (tal vez debido a las pequeñas flechas que los campos de texto no tienen).

Mi solución

Agregué un keyupcontrolador de eventos a la entrada del formulario y rastreé el estado y configuré el valor una vez que vuelve a ser válido.

Fragmento JS puro JSFIDDLE

Fragmento angular 9

Joniras
fuente
0

¿Mi recomendación? No use jQuery en absoluto. Yo tenía el mismo problema que tú. Encontré que $('#my_input').val()siempre devuelve algún resultado extraño.

Intente usar en document.getElementById('my_input').valueAsNumberlugar de $("#my_input").val();y luego, use Number(your_value_retrieved)para intentar crear un Número. Si el valor es NaN, seguramente sabe que no es un número.

Una cosa para agregar es que cuando escribe un número en la entrada, la entrada aceptará casi cualquier carácter (puedo escribir el símbolo del euro, un dólar y todos los demás caracteres especiales), por lo que es mejor recuperar el valor usando .valueAsNumberen lugar de usar jQuery.

Ah, y por cierto, eso permite a sus usuarios agregar internacionalización (es decir: admite comas en lugar de puntos para crear números decimales). Simplemente deje que el Number()objeto cree algo para usted y será decimal seguro, por así decirlo.

Patrick D'appollonio
fuente
El problema no es causado por jQuery, y creo que valueAsNumbertampoco funciona de manera consistente en los navegadores.
bert bruynooghe
0

Parece que le gustaría usar toLocaleString () en sus entradas numéricas.

Ver https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString para su uso.

La localización de números en JS también está cubierta en Internacionalización (el formato de número "num.toLocaleString ()") no funciona para Chrome

stackasec
fuente
2
Es habitual dar más explicaciones de la solución, incluso si la respuesta está completamente cubierta por contenido vinculado.
IvanH
Este enfoque parece ser mejor que los otros enfoques si el servidor de fondo está determinando la configuración regional en lugar del navegador en sí. Desafortunadamente, toLocaleStringno es confiable en todas las plataformas.
bert bruynooghe
El soporte multiplataforma me parece lo suficientemente amplio en 2015, ver, por ejemplo, Mozillas Devnet . Sin embargo, si aún le preocupa, encuentre las posibles soluciones aquí.
stackasec
Mozillas Devnet no muestra casi ninguna compatibilidad para navegadores móviles, y ahí es exactamente donde el campo de texto numérico puede ofrecer la mayoría de los beneficios. (Ver pregunta original.)
bert bruynooghe
... y se han mostrado y referenciado alternativas más que suficientes. Que te diviertas.
stackasec