Comment gérer les flottants et les séparateurs décimaux avec un numéro de type d'entrée HTML5

128

Je construis une application Web qui est principalement destinée aux navigateurs mobiles. J'utilise des champs de saisie avec le type de nombre, donc (la plupart) les navigateurs mobiles n'appellent que le clavier numérique pour une meilleure expérience utilisateur. Cette application Web est principalement utilisée dans les régions où le séparateur décimal est une virgule, pas un point, je dois donc gérer les deux séparateurs décimaux.

Comment couvrir tout ce désordre avec des points et des virgules?

Mes découvertes:

Chrome de bureau

  • Type d'entrée = nombre
  • L'utilisateur entre «4,55» dans le champ de saisie
  • $("#my_input").val(); renvoie "455"
  • Je ne peux pas obtenir la valeur correcte de l'entrée

Firefox de bureau

  • Type d'entrée = nombre
  • L'utilisateur entre «4,55» dans le champ de saisie
  • $("#my_input").val(); renvoie "4,55"
  • C'est bien, je peux remplacer la virgule par un point et obtenir un flotteur correct

Navigateur Android

  • Type d'entrée = nombre
  • L'utilisateur entre «4,55» dans le champ de saisie
  • Lorsque l'entrée perd le focus, la valeur est tronquée à "4"
  • Confus pour l'utilisateur

Windows Phone 8

  • Type d'entrée = nombre
  • L'utilisateur entre «4,55» dans le champ de saisie
  • $("#my_input").val(); renvoie "4,55"
  • C'est bien, je peux remplacer la virgule par un point et obtenir un flotteur correct

Quelles sont les «meilleures pratiques» dans ce genre de situations lorsque l'utilisateur peut utiliser une virgule ou un point comme séparateur décimal et que je souhaite conserver le type d'entrée html sous forme de nombre, afin de fournir une meilleure expérience utilisateur?

Puis-je convertir une virgule en point "à la volée", lier les événements clés, fonctionne-t-il avec des entrées numériques?

ÉDITER

Currenlty Je n'ai aucune solution, comment obtenir une valeur flottante (sous forme de chaîne ou de nombre) à partir de l'entrée dont le type est défini sur nombre. Si l'utilisateur final entre «4,55», Chrome renvoie toujours «455», Firefox renvoie «4,55», ce qui est très bien.

De plus, il est assez ennuyeux que dans Android (émulateur 4.2 testé), lorsque j'entre "4,55" dans le champ de saisie et que je change le focus vers un autre endroit, le nombre entré soit tronqué à "4".

devha
la source
Je suppose que la cause première de certains de vos problèmes est que les navigateurs sont définis sur un paramètre régional américain qui utilise le point comme séparateur décimal. Il semble que Chrome et Android soient confondus de différentes manières: Chrome traite la virgule comme un séparateur de chiffres, puis convertit l'entrée en nombre, puis la convertit à nouveau en une chaîne pour .val(), et Android fait quelque chose de bizarre. Pouvez-vous vérifier s'ils se comportent de la même manière lorsque vous définissez la langue du système sur quelque chose de approprié?
millimoose
1
Nvm a publié ceci comme une réponse
kjetilh
Voir aussi ici: stackoverflow.com/a/24423879/196210
Revious
La situation est encore pire que celle que vous avez décrite: vous obtenez un point décimal ou une virgule sur le pavé numérique WP en fonction de la langue sur laquelle vous avez choisi votre clavier. Il n'y a également aucun moyen de savoir quelle était la locale d'entrée (pas nécessairement la langue préférée du navigateur) ... Donc le mieux que je puisse trouver (et ce qui est assez bon pour moi) est: var number = $(...).get(0).valueAsNumber; if (isNaN(number)) number = parseFloat($(...).val().replace(',', '.'); Mais cette solution ne fonctionne que si le le nombre qui a été mis ne contient qu'une virgule et aucun point supplémentaire ...
bert bruynooghe

Réponses:

107

Je pense que ce qui manque dans les réponses ci-dessus, c'est la nécessité de spécifier une valeur différente pour l' stepattribut, qui a une valeur par défaut de 1. Si vous souhaitez que l'algorithme de validation de l'entrée autorise les valeurs à virgule flottante, spécifiez une étape en conséquence.

Par exemple, je voulais des montants en dollars, j'ai donc spécifié une étape comme celle-ci:

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

Il n'y a rien de mal à utiliser jQuery pour récupérer la valeur, mais vous trouverez utile d'utiliser directement l'API DOM pour obtenir la validity.validpropriété des éléments .

J'ai eu un problème similaire avec le point décimal, mais la raison pour laquelle j'ai réalisé qu'il y avait un problème était à cause du style que Twitter Bootstrap ajoute à une entrée numérique avec une valeur invalide.

Voici un violon démontrant que l'ajout de l' stepattribut le fait fonctionner, et testant également si la valeur actuelle est valide:

TL; DR: définissez l' stepattribut a sur une valeur à virgule flottante, car il est par défaut 1.

REMARQUE : la virgule ne valide pas pour moi, mais je soupçonne que si je définis les paramètres de langue / région de mon système d'exploitation à un endroit qui utilise une virgule comme séparateur décimal, cela fonctionnerait. * note en note *: ce n'était pas le cas pour les paramètres de langue / clavier du système d'exploitation * Allemand * dans Ubuntu / Gnome 14.04.

natchiketa
la source
8
Si vous souhaitez autoriser arbitrairement plusieurs décimales, spécifiez l' stepattribut comme "any"au lieu de, par exemple, "0.01"comme indiqué ici. Voir cette version modifiée du violon de nathciketa pour une démo.
Mark Amery
4
J'ai également rencontré des problèmes avec des virgules ne validant pas, bien que j'aie entré "1,234.56" <input type="number" step="any">. Je n'ai pas été en mesure de trouver un moyen de désactiver la validation HTML5. Je peux désactiver ou personnaliser le message d'erreur, mais récupérer la valeur de l'entrée est toujours un jeu de dés. Des idées?
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.Donc, le motif est inutile avectype="number"
Michael Laffargue
comme Michael l'a dit, veuillez changer le typeen text, sinon votre réponse n'a aucun sens.
phil294
23

Selon w3.org, l' attribut value de l' entrée numérique est défini comme un nombre à virgule flottante . La syntaxe du nombre à virgule flottante semble n'accepter que les points comme séparateurs décimaux.

J'ai répertorié ci-dessous quelques options qui pourraient vous être utiles:

1. Utilisation de l'attribut pattern

Avec l' attribut pattern, vous pouvez spécifier le format autorisé avec une expression régulière d'une manière compatible HTML5. Ici, vous pouvez spécifier que le caractère virgule est autorisé et un message de retour utile si le modèle échoue.

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

Remarque: la prise en charge de plusieurs navigateurs varie beaucoup. Il peut être complet, partiel ou inexistant.

2. Validation JavaScript

Vous pouvez essayer de lier un simple rappel à, par exemple, l' événement onchange (et / ou flou ) qui remplacerait la virgule ou validerait tous ensemble.

3. Désactivez la validation du navigateur ##

Troisièmement, vous pouvez essayer d'utiliser l' attribut formnovalidate sur les entrées numériques dans le but de désactiver la validation du navigateur pour ce champ dans son ensemble.

<input type="number" formnovalidate />

4. Combinaison ..?

<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
la source
2
input.valueAsNumber - Aucune aide car cela ne fonctionne qu'avec des points comme séparateur décimal et dans mon cas, l'utilisateur final peut utiliser un point ou une virgule. Form tag novalidate - N'ont trouvé aucun effet à ce sujet.
devha
Malheureusement, je suis à court d'idées, donc je ne suis pas sûr que vous puissiez faire fonctionner ce navigateur multi-navigateur sans solution de contournement. J'ai mis à jour ma réponse pour inclure l' attribut de modèle. J'ai également trouvé que l'on peut utiliser l' attribut formnovalidate directement sur les champs de saisie. Je sais que vous ne l'aimerez pas mais si tout échoue et que vous avez absolument besoin de virgules, input = "text" pourrait être le seul moyen ..
kjetilh
Il semble que le numéro de type d'entrée génère plus de problèmes qu'il n'améliore réellement l'expérience utilisateur. Dans un appareil mobile, ce serait génial si je ne peux ouvrir que le clavier numérique à l'utilisateur si je veux qu'il n'entre que des chiffres. Quoi qu'il en soit, je dois repenser cela une fois de plus ...
devha
Comme nous devons également prendre en charge l'utilisation du point et de la virgule comme séparateur décimal, nous prévoyons d'utiliser un modèle pour la validation sur le bureau en combinaison avec type = "text". Ensuite, nous ajouterons la détection des fonctionnalités pour détecter les appareils mobiles et utiliserons type = "number" lorsque cela s'applique.
awe
9

L'utilisation d'une virgule ou d'un point pour le séparateur décimal dépend entièrement du navigateur. Le navigateur prend sa décision en fonction des paramètres régionaux du système d'exploitation ou du navigateur, ou certains navigateurs prennent des indices sur le site Web. J'ai créé un tableau de comparaison des navigateurs montrant comment différents navigateurs prennent en charge différentes méthodes de localisation. Safari étant le seul navigateur à gérer les virgules et les points de manière interchangeable.

Fondamentalement, en tant qu'auteur Web, vous ne pouvez pas vraiment contrôler cela. Certaines solutions de contournement impliquent l'utilisation de deux champs d'entrée avec des entiers. Cela permet à chaque utilisateur de saisir les données comme prévu. Ce n'est pas particulièrement sexy, mais cela fonctionnera dans tous les cas pour tous les utilisateurs.

Aeyoun
la source
7

Utilisez à la valueAsNumberplace de .val().

contribution . valueAsNumber [= valeur]

Renvoie un nombre représentant la valeur du contrôle de formulaire, le cas échéant; sinon, retourne null.
Peut être défini, pour changer la valeur.
Lève une exception INVALID_STATE_ERR si le contrôle n'est ni basé sur la date ou l'heure ni numérique.

Mike Samuel
la source
2
Le problème est qu'il veut prendre en charge la virgule comme séparateur décimal, et l'utilisation de type = "number" sur l'entrée donne toujours un nombre invalide lors de l'écriture d'une virgule.
awe
Semble ne pas fonctionner de manière cohérente sur Windows Phone; revient toujours NaN.
bert bruynooghe le
@bertbruynooghe, quelle valeur attribuez-vous?
Mike Samuel
Cela ne semble pas fonctionner, ni avec «9», «9,1», «9.1». Le téléphone est configuré aux États-Unis, les dispositions de clavier sont testées en-US, nl-BE.
bert bruynooghe
4

utilise un type de texte mais force l'apparence du clavier numérique

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

la balise inputmode est la solution

David Navarro
la source
Mais il n'est pas compatible avec tous les navigateurs, uniquement avec les dernières versions d'iOS Safari, Chrome, Chromium, Opera ... caniuse.com/#feat=input-inputmode :(
pgarciacamou
De plus, vous n'obtenez pas ce clavier numérique soigné sur les appareils mobiles.
WoIIe
3

Je n'ai pas trouvé de solution parfaite mais le mieux que je puisse faire était d'utiliser type = "tel" et de désactiver la validation html5 (formnovalidate):

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

Si l'utilisateur met une virgule, il affichera la virgule dans chaque navigateur moderne que j'ai essayé (dernier FF, IE, bord, opéra, chrome, bureau safari, chrome android).

Le problème principal est:

  • Les utilisateurs mobiles verront le clavier de leur téléphone qui peut être différent du clavier numérique.
  • Pire encore, le clavier du téléphone peut même ne pas avoir de touche pour une virgule.

Pour mon cas d'utilisation, je n'avais qu'à:

  • Afficher la valeur initiale avec une virgule (Firefox la supprime pour type = nombre)
  • Ne pas échouer à la validation html5 (s'il y a une virgule)
  • Faites lire le champ exactement comme entrée (avec une virgule possible)

Si vous avez une exigence similaire, cela devrait fonctionner pour vous.

Remarque: je n'ai pas aimé le support de l'attribut pattern. Le formnovalidate semble fonctionner beaucoup mieux.

Bolo
la source
1

Lorsque vous appelez, $("#my_input").val();il retourne sous forme de variable de chaîne. Alors utilisez parseFloatet parseIntpour convertir. Lorsque vous utilisez parseFloatvotre ordinateur de bureau ou votre téléphone, LUI-MÊME comprend la signification de variable.

Et en plus, vous pouvez convertir un flottant en chaîne en utilisant toFixedqui a un argument le nombre de chiffres comme ci-dessous:

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

la source
Ne marche pas. Essayez parseFloat ("1,5") dans IE11. Renvoie 1. La langue est l'allemand pour OS et IE.
T3rm1
1

Apparemment, les navigateurs ont encore des problèmes (bien que Chrome et Firefox Nightly fonctionnent bien). J'ai une approche hacky pour les personnes qui doivent vraiment utiliser un champ numérique (peut-être à cause des petites flèches que les champs de texte n'ont pas).

Ma solution

J'ai ajouté un keyupgestionnaire d'événements à l'entrée du formulaire, suivi de l'état et défini la valeur une fois qu'elle est à nouveau valide.

Extrait JS pur JSFIDDLE

Extrait angulaire 9

Joniras
la source
0

Ma recommandation? N'utilisez pas du tout jQuery. J'ai eu le même problème que toi. J'ai trouvé que cela $('#my_input').val()retournait toujours un résultat étrange.

Essayez d'utiliser à la document.getElementById('my_input').valueAsNumberplace de $("#my_input").val();, puis utilisez Number(your_value_retrieved)pour essayer de créer un nombre. Si la valeur est NaN, vous savez certainement que ce n'est pas un nombre.

Une chose à ajouter est que lorsque vous écrivez un nombre sur l'entrée, l'entrée accepte en fait presque tous les caractères (je peux écrire le signe euro, un dollar et tous les autres caractères spéciaux), il est donc préférable de récupérer la valeur en utilisant .valueAsNumberau lieu d'utiliser jQuery.

Oh, et BTW, qui permet à vos utilisateurs d'ajouter l'internationalisation (c'est-à-dire: prendre en charge les virgules au lieu des points pour créer des nombres décimaux). Laissez simplement l' Number()objet créer quelque chose pour vous et il sera sans danger pour les décimales, pour ainsi dire.

Patrick D'appollonio
la source
Le problème n'est pas causé par jQuery, et je trouve que cela valueAsNumberne fonctionne pas de manière cohérente avec les navigateurs.
bert bruynooghe le
0

On dirait que vous souhaitez utiliser toLocaleString () sur vos entrées numériques.

Voir https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString pour son utilisation.

La localisation des nombres dans JS est également traitée dans Internationalisation (le formatage des nombres "num.toLocaleString ()") ne fonctionne pas pour Chrome

stackasec
la source
2
Il est habituel de donner plus d'explications sur la solution même si la réponse est entièrement couverte par le contenu lié.
IvanH
Cette approche semble être meilleure que les autres approches si le serveur principal détermine les paramètres régionaux plutôt que le navigateur lui-même. Malheureusement, toLocaleStringn'est pas fiable sur toutes les plates-formes.
bert bruynooghe le
Le support multiplateforme me semble assez large en 2015, voir par exemple Mozillas Devnet . Cependant, si cela vous préoccupe toujours, trouvez des solutions possibles ici.
stackasec
Mozillas Devnet ne montre presque aucune compatibilité pour les navigateurs mobiles, et c'est exactement là que le champ de texte numérique peut offrir le plus d'avantages. (Voir la question d'origine.)
bert bruynooghe
... et plus qu'assez d'alternatives ont été montrées et référencées. S'amuser.
stackasec