Como lidar com flutuadores e separadores decimais com o número do tipo de entrada html5

128

Estou criando um aplicativo da Web que é principalmente para navegadores móveis. Como estou usando campos de entrada com o tipo de número, a maioria dos navegadores móveis chama apenas o teclado numérico para melhorar a experiência do usuário. Este aplicativo da Web é usado principalmente em regiões onde o separador decimal é vírgula, não ponto, por isso preciso lidar com os dois separadores decimais.

Como cobrir toda essa bagunça com ponto e vírgula?

Minhas descobertas:

Chrome para computador

  • Tipo de entrada = número
  • O usuário digita "4,55" no campo de entrada
  • $("#my_input").val(); retorna "455"
  • Não consigo obter o valor correto da entrada

Desktop Firefox

  • Tipo de entrada = número
  • O usuário digita "4,55" no campo de entrada
  • $("#my_input").val(); retorna "4,55"
  • Tudo bem, eu posso substituir vírgula por ponto e obter a flutuação correta

Navegador Android

  • Tipo de entrada = número
  • O usuário digita "4,55" no campo de entrada
  • Quando a entrada perde o foco, o valor é truncado para "4"
  • Confuso para o usuário

Windows Phone 8

  • Tipo de entrada = número
  • O usuário digita "4,55" no campo de entrada
  • $("#my_input").val(); retorna "4,55"
  • Tudo bem, eu posso substituir vírgula por ponto e obter a flutuação correta

Quais são as "melhores práticas" nesse tipo de situação em que o usuário pode usar vírgula ou ponto como separador decimal e eu quero manter o tipo de entrada html como número, para proporcionar uma melhor experiência ao usuário?

Posso converter vírgula em ponto "on the fly", vinculando eventos importantes, está funcionando com entradas numéricas?

EDITAR

Atualmente, eu não tenho nenhuma solução, como obter valor flutuante (como string ou número) da entrada que tipo está definido como número. Se o usuário final digitar "4,55", o Chrome sempre retornará "455", o Firefox retornará "4,55", o que é bom.

Também é bastante irritante que no Android (emulador 4.2 testado), quando eu digito "4,55" para inserir o campo e mudo o foco para outro lugar, o número digitado seja truncado para "4".

devha
fonte
Meu palpite é que a causa principal de alguns dos seus problemas é que os navegadores estão configurados para um código de idioma dos EUA que usa o ponto como um separador decimal. Parece que o Chrome e o Android estão ficando confusos com isso de diferentes maneiras - o Chrome trata a vírgula como um separador de dígitos, depois converte a entrada em um número e depois em uma string novamente .val(), e o Android faz algo estranho. Você pode verificar se eles se comportam da mesma maneira quando você define o idioma do sistema para algo apropriado?
millimoose
1
Nvm postou isso como uma resposta
kjetilh 8/13
Veja também aqui: stackoverflow.com/a/24423879/196210
Revious
A situação é ainda pior do que você imaginou: você obtém um ponto decimal ou vírgula no WP numpad, dependendo do idioma em que você escolheu o teclado para trabalhar. Também não há como descobrir qual era o código de idioma de entrada (não necessariamente o idioma preferido do navegador) ... Portanto, o melhor que pude apresentar (e o que é bom o suficiente para mim) é: var number = $(...).get(0).valueAsNumber; if (isNaN(number)) number = parseFloat($(...).val().replace(',', '.'); Mas essa solução só funciona se o número que tem sido posta em apenas contém uma vírgula e sem pontos extras ...
bert bruynooghe

Respostas:

107

Acho que o que falta nas respostas acima é a necessidade de especificar um valor diferente para o stepatributo, que tem um valor padrão de 1. Se você deseja que o algoritmo de validação da entrada permita valores de ponto flutuante, especifique uma etapa de acordo.

Por exemplo, eu queria quantias em dólares, então especifiquei uma etapa como esta:

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

Não há nada errado em usar o jQuery para recuperar o valor, mas você achará útil usar a API DOM diretamente para obter a validity.validpropriedade dos elementos .

Eu tive um problema semelhante com o ponto decimal, mas a razão pela qual percebi que havia um problema era devido ao estilo que o Twitter Bootstrap adiciona a uma entrada de número com um valor inválido.

Aqui está um violino demonstrando que a adição do stepatributo o faz funcionar e também testando se o valor atual é válido:

TL; DR: defina o stepatributo a como um valor de ponto flutuante, porque o padrão é 1.

NOTA : A vírgula não é válida para mim, mas suspeito que, se eu definir as configurações de idioma / região do SO em algum lugar que use uma vírgula como separador decimal, funcionará. * note in note *: esse não foi o caso das configurações de idioma / teclado do SO * alemão * no Ubuntu / Gnome 14.04.

natchiketa
fonte
8
Se você deseja permitir arbitrariamente muitas casas decimais, especifique o stepatributo como em "any"vez de, por exemplo, "0.01"como mostrado aqui. Veja esta versão aprimorada do violino de nathciketa para uma demonstração.
Mark Amery
4
Também tive problemas com vírgulas que não estavam validando, apesar de inserir "1.234,56" <input type="number" step="any">. Não consegui encontrar uma maneira de desativar a validação HTML5. Posso desativar ou personalizar a mensagem de erro, mas recuperar o valor da entrada é sempre um dado de craps. Alguma ideia?
Nick G.
5
This attribute applies when the value of the type attribute is text, search, tel, url, email, or password, otherwise it is ignored.Então, o padrão é inútil comtype="number"
Michael Laffargue
como Michael disse, altere typepara text, caso contrário, sua resposta não faz sentido.
phil294
23

Segundo o w3.org, o atributo value da entrada numérica é definido como um número de ponto flutuante . A sintaxe do número de ponto flutuante parece aceitar apenas pontos como separadores decimais.

Listei algumas opções abaixo que podem ser úteis para você:

1. Usando o atributo padrão

Com o atributo padrão, você pode especificar o formato permitido com uma expressão regular de forma compatível com HTML5. Aqui você pode especificar que o caractere de vírgula é permitido e uma mensagem de feedback útil se o padrão falhar.

<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: O suporte entre navegadores varia muito. Pode ser completo, parcial ou inexistente.

2. Validação de JavaScript

Você pode tentar vincular um retorno de chamada simples a, por exemplo, o evento onchange (e / ou blur ) que substituiria a vírgula ou validaria todos juntos.

3. Desative a validação do navegador ##

Em terceiro lugar, você poderia tentar usar o atributo formnovalidate nas entradas numéricas com a intenção de desativar a validação do navegador para esse campo todos juntos.

<input type="number" formnovalidate />

4. Combinação ..?

<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
fonte
2
input.valueAsNumber - Nenhuma ajuda, pois isso funciona apenas com pontos como separador decimal e, no meu caso, o usuário final pode usar ponto ou vírgula. Tag de formulário novalidate - não encontrou nenhum efeito nisso.
devha
Infelizmente, estou ficando sem ideias, por isso não tenho certeza se você é capaz de fazer esse trabalho entre navegadores sem uma solução alternativa. Atualizei minha resposta para incluir o atributo padrão . Também achei que se pode usar o atributo formnovalidate diretamente nos campos de entrada. Eu sei que você não vai gostar, mas se tudo falhar e você precisa absolutamente vírgulas depois de entrada = "text" pode ser a única maneira ..
kjetilh
Parece que o número do tipo de entrada gera mais problemas do que realmente melhora a experiência do usuário. No dispositivo móvel, seria ótimo se eu pudesse abrir apenas o teclado numérico para o usuário, se quiser que ele insira apenas números. De qualquer forma eu preciso repensar isso mais uma vez ...
devha
Como também precisamos oferecer suporte ao uso de ponto e vírgula como separador decimal, planejamos usar o padrão para validação na área de trabalho em combinação com type = "text". Em seguida, adicionaremos a detecção de recursos para a detecção de dispositivos móveis e usaremos type = "number" quando isso for aplicável.
temor
9

O uso de vírgula ou ponto no separador decimal depende inteiramente do navegador. O navegador toma sua decisão com base na localidade do sistema operacional ou do navegador, ou alguns navegadores recebem dicas do site. Fiz um gráfico de comparação de navegadores mostrando como diferentes navegadores suportam os diferentes métodos de localização. O Safari é o único navegador que manipula vírgulas e períodos de forma intercambiável.

Basicamente, você como autor da Web não pode realmente controlar isso. Algumas soluções alternativas envolvem o uso de dois campos de entrada com números inteiros. Isso permite que cada usuário insira os dados conforme o esperado. Não é particularmente sexy, mas funcionará em todos os casos para todos os usuários.

Aeyoun
fonte
7

Use em valueAsNumbervez de .val().

entrada . valueAsNumber [= value]

Retorna um número que representa o valor do controle de formulário, se aplicável; caso contrário, retorna nulo.
Pode ser definido, para alterar o valor.
Lança uma exceção INVALID_STATE_ERR se o controle não for baseado em data ou hora, nem numérico.

Mike Samuel
fonte
2
O problema é que ele deseja suportar vírgula como separador decimal, e usar type = "number" na entrada sempre fornece um número inválido ao escrever vírgula.
temor
Parece não funcionar consistentemente no Windows Phone; sempre retorna NaN.
bert bruynooghe
@bertbruynooghe, O que você está atribuindo como valor?
Mike Samuel
Parece não funcionar, nem com '9', '9,1', '9,1'. O telefone está configurado como EUA, layouts de teclado testados en-US, nl-BE.
22715
4

usa um tipo de texto, mas força a aparência do teclado numérico

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

a tag inputmode é a solução

David Navarro
fonte
Mas não é compatível com todos os navegadores, apenas com versões mais recentes do iOS Safari, Chrome, Chromium, Opera ... caniuse.com/#feat=input-inputmode :(
pgarciacamou
Além disso, você não recebe este teclado numérico elegante em dispositivos móveis.
WoIIe
3

Não encontrei uma solução perfeita, mas o melhor que pude fazer foi usar type = "tel" e desativar a validação html5 (formnovalidate):

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

Se o usuário colocar uma vírgula, ele será gerado com a vírgula em todos os navegadores modernos que tentei (mais recentes FF, IE, edge, opera, chrome, safari desktop, android chrome).

O principal problema é:

  • Os usuários móveis verão o teclado do telefone, que pode ser diferente do teclado numérico.
  • Pior ainda, o teclado do telefone pode nem ter uma tecla para vírgula.

Para o meu caso de uso, eu só precisava:

  • Exibir o valor inicial com uma vírgula (o Firefox o remove para type = number)
  • Não falha na validação html5 (se houver vírgula)
  • Faça com que o campo seja lido exatamente como entrada (com uma possível vírgula)

Se você tiver um requisito semelhante, isso deve funcionar para você.

Nota: Não gostei do suporte do atributo pattern. O formnovalidato parece funcionar muito melhor.

Bolo
fonte
1

Quando você chama $("#my_input").val();, retorna como variável de string. Então use parseFloate parseIntpara converter. Quando você usa parseFloatsua área de trabalho ou telefone, o ITSELF entende o significado de variável.

Além disso, você pode converter um float em string usando o toFixedqual possui um argumento a contagem de dígitos conforme abaixo:

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

fonte
Não funciona. Tente parseFloat ("1,5") no IE11. Retorna 1. O idioma é alemão para OS e IE.
T3rm1
1

Aparentemente, os navegadores ainda têm problemas (embora o Chrome e o Firefox Nightly estejam bem). Eu tenho uma abordagem hacky para as pessoas que realmente precisam usar um campo numérico (talvez por causa das pequenas flechas que os campos de texto não possuem).

Minha solução

Adicionei um keyupmanipulador de eventos à entrada do formulário e rastreie o estado e defina o valor assim que ele for válido novamente.

Snippet JS puro JSFIDDLE

Snippet angular 9

Joniras
fonte
0

Minha recomendação? Não use jQuery. Eu tive o mesmo problema que você. Eu descobri que $('#my_input').val()sempre retorna algum resultado estranho.

Tente usar em document.getElementById('my_input').valueAsNumbervez de $("#my_input").val();e, em seguida, use Number(your_value_retrieved)para tentar criar um número. Se o valor for NaN, você certamente sabe que isso não é um número.

Uma coisa a acrescentar é que, quando você escreve um número na entrada, ela realmente aceita quase qualquer caractere (eu posso escrever o sinal do euro, um dólar e todos os outros caracteres especiais); portanto, é melhor recuperar o valor usando .valueAsNumberem vez de usar jQuery.

Ah, e BTW, isso permite que seus usuários adicionem internacionalização (por exemplo: vírgulas de suporte em vez de pontos para criar números decimais). Apenas deixe o Number()objeto criar algo para você e ele será seguro como decimal, por assim dizer.

Patrick D'appollonio
fonte
O problema não é causado pelo jQuery, e acho que valueAsNumbertambém não está funcionando de maneira consistente nos navegadores.
bert bruynooghe
0

Parece que você gostaria de usar toLocaleString () em suas entradas numéricas.

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

A localização de números em JS também é abordada em Internacionalização (a formatação de números "num.toLocaleString ()") não funciona no chrome

stackasec
fonte
2
É comum dar mais explicações sobre a solução, mesmo que a resposta seja totalmente coberta pelo conteúdo vinculado.
IvanH 30/05
Essa abordagem parece ser melhor do que as outras abordagens se o servidor back-end determinar o local e não o navegador. Infelizmente, toLocaleStringnão é confiável entre plataformas.
bert bruynooghe
O suporte a várias plataformas parece amplo o suficiente para mim em 2015, veja, por exemplo, o Mozillas Devnet . No entanto, se ainda lhe interessa, encontre possíveis soluções aqui.
stackasec
O Mozillas Devnet não mostra quase nenhuma compatibilidade com navegadores móveis, e é exatamente aí que o campo de texto numérico pode oferecer mais benefícios. (Veja pergunta original.)
bert bruynooghe
... e alternativas mais que suficientes foram mostradas e referenciadas. Diverta-se.
stackasec