Jak obsługiwać liczby zmiennoprzecinkowe i separatory dziesiętne za pomocą numeru typu danych wejściowych html5

132

Tworzę aplikację internetową przeznaczoną głównie dla przeglądarek mobilnych. Używam pól wejściowych z typem liczbowym, więc (większość) przeglądarek mobilnych wywołuje tylko klawiaturę numeryczną dla lepszego doświadczenia użytkownika. Ta aplikacja internetowa jest używana głównie w regionach, w których separatorem dziesiętnym jest przecinek, a nie kropka, więc muszę obsługiwać oba separatory dziesiętne.

Jak zakryć ten cały bałagan kropką i przecinkiem?

Moje ustalenia:

Chrome na komputer

  • Typ danych wejściowych = liczba
  • Użytkownik wpisuje „4,55” w polu wprowadzania
  • $("#my_input").val(); zwraca „455”
  • Nie mogę uzyskać prawidłowej wartości z danych wejściowych

Firefox na komputer

  • Typ danych wejściowych = liczba
  • Użytkownik wpisuje „4,55” w polu wprowadzania
  • $("#my_input").val(); zwraca „4,55”
  • W porządku, mogę zastąpić przecinek kropką i uzyskać poprawny float

Przeglądarka Android

  • Typ danych wejściowych = liczba
  • Użytkownik wpisuje „4,55” w polu wprowadzania
  • Gdy dane wejściowe tracą fokus, wartość jest obcinana do „4”
  • Mylące dla użytkownika

Windows Phone 8

  • Typ danych wejściowych = liczba
  • Użytkownik wpisuje „4,55” w polu wprowadzania
  • $("#my_input").val(); zwraca „4,55”
  • W porządku, mogę zastąpić przecinek kropką i uzyskać poprawny float

Jakie są „sprawdzone metody” w tego rodzaju sytuacjach, gdy użytkownik może użyć przecinka lub kropki jako separatora dziesiętnego, a ja chcę, aby typ wejściowy HTML był liczbą, aby zapewnić użytkownikom lepsze wrażenia?

Czy mogę zamienić przecinek na kropkę „w locie”, wiążąc kluczowe zdarzenia, czy to działa z wejściami liczbowymi?

EDYTOWAĆ

Obecnie nie mam żadnego rozwiązania, jak uzyskać wartość zmiennoprzecinkową (jako ciąg lub liczbę) z wejścia, którego typ jest ustawiony na liczbę. Jeśli użytkownik końcowy wpisze „4,55”, Chrome zwróci zawsze „455”, Firefox zwróci „4,55”, co jest w porządku.

Dość denerwujące jest też to, że w Androidzie (testowany emulator 4.2), kiedy wpisuję „4,55” w polu wprowadzania i zmieniam fokus na gdzieś indziej, to wpisana liczba zostaje obcięta do „4”.

devha
źródło
Domyślam się, że główną przyczyną niektórych problemów jest to, że przeglądarki są ustawione na ustawienia regionalne dla Stanów Zjednoczonych, które używają kropki jako separatora dziesiętnego. Wygląda na to, że Chrome i Android są mylone przez to na różne sposoby - Chrome traktuje przecinek jako separator cyfr, następnie konwertuje dane wejściowe na liczbę, a następnie konwertuje je ponownie na ciąg znaków .val(), a Android robi coś dziwnego. Czy możesz sprawdzić, czy zachowują się tak samo, gdy ustawisz język systemu na coś odpowiedniego?
millimoose
1
Nvm opublikował to jako odpowiedź
kjetilh
Zobacz także tutaj: stackoverflow.com/a/24423879/196210
Revious
Sytuacja jest jeszcze gorsza, niż przedstawiłeś: na klawiaturze numerycznej WP znajduje się przecinek dziesiętny lub przecinek, w zależności od języka, w którym wybrałeś klawiaturę do pracy. Nie ma również sposobu, aby dowiedzieć się, który był językiem wejściowym (niekoniecznie preferowanym językiem przeglądarki) ... Więc najlepsze, co mogłem wymyślić (i co jest dla mnie wystarczająco dobre), to: var number = $(...).get(0).valueAsNumber; if (isNaN(number)) number = parseFloat($(...).val().replace(',', '.'); Ale to rozwiązanie działa tylko wtedy, gdy numer, który został wstawiony zawiera tylko 1 przecinek i żadnych dodatkowych kropek ...
bert bruynooghe

Odpowiedzi:

109

Myślę, że w powyższych odpowiedziach brakuje konieczności określenia innej wartości stepatrybutu, który ma domyślną wartość1 . Jeśli chcesz, aby algorytm walidacji danych wejściowych zezwalał na wartości zmiennoprzecinkowe, określ odpowiednio krok.

Na przykład chciałem kwot w dolarach, więc określiłem krok taki:

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

Nie ma nic złego w używaniu jQuery do pobierania wartości, ale okaże się przydatne bezpośrednie użycie interfejsu API DOM do uzyskania wartości elementów validity.valid .

Miałem podobny problem z przecinkiem dziesiętnym, ale powodem, dla którego zdałem sobie sprawę, że wystąpił problem, był styl, który Twitter Bootstrap dodaje do danych wejściowych z nieprawidłową wartością.

Oto skrzypce pokazujące, że dodanie stepatrybutu sprawia, że ​​działa, a także testujące, czy bieżąca wartość jest prawidłowa:

TL; DR: Ustaw stepatrybut a na wartość zmiennoprzecinkową, ponieważ domyślnie 1.

UWAGA : Przecinek nie sprawdza się dla mnie, ale podejrzewam, że jeśli ustawię ustawienia języka / regionu systemu operacyjnego na miejsce, w którym jako separator dziesiętny jest używany przecinek, zadziała. * uwaga w uwadze *: tak nie było w przypadku ustawień języka systemu operacyjnego / klawiatury * niemieckiego * w Ubuntu / Gnome 14.04.

natchiketa
źródło
8
Jeśli chcesz zezwolić na dowolną liczbę miejsc dziesiętnych, określ stepatrybut jako "any"zamiast np. "0.01"Jak pokazano tutaj. Zobacz tę ulepszoną wersję skrzypiec nathciketa, aby zobaczyć demo.
Mark Amery,
4
Napotkałem również problemy z przecinkami, które nie sprawdzały się, chociaż wprowadzałem „1,234,56” w <input type="number" step="any">. Nie udało mi się znaleźć sposobu, aby wyłączyć walidację HTML5. Mogę wyłączyć lub dostosować komunikat o błędzie, ale pobieranie wartości z danych wejściowych jest zawsze bzdurą. Jakieś pomysły?
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.Tak więc wzór jest bezużyteczny ztype="number"
Michael Laffargue
jak powiedział Michael, proszę zmienić typesię text, w przeciwnym razie odpowiedź nie mają żadnego sensu.
phil294
23

Według serwisu w3.org atrybut wartości liczby wejściowej jest zdefiniowany jako liczba zmiennoprzecinkowa . Składnia liczby zmiennoprzecinkowej wydaje się akceptować tylko kropki jako separatory dziesiętne.

Poniżej wymieniłem kilka opcji, które mogą być pomocne:

1. Korzystanie z atrybutu pattern

Za pomocą atrybutu wzorzec możesz określić dozwolony format za pomocą wyrażenia regularnego w sposób zgodny z HTML5. W tym miejscu możesz określić, że znak przecinka jest dozwolony i pomocny komunikat zwrotny, jeśli wzorzec nie powiedzie się.

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

Uwaga: obsługa wielu przeglądarek jest bardzo różna. Może być kompletny, częściowy lub nie istnieje.

2. Walidacja JavaScript

Możesz spróbować powiązać proste wywołanie zwrotne na przykład ze zdarzeniem onchange (i / lub rozmycie ), które albo zastąpi przecinek, albo zweryfikuje wszystko razem.

3. Wyłącz sprawdzanie poprawności przeglądarki ##

Po trzecie, możesz spróbować użyć atrybutu formnovalidate na wejściach liczbowych z zamiarem całkowitego wyłączenia weryfikacji przeglądarki dla tego pola.

<input type="number" formnovalidate />

4. Połączenie…?

<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
źródło
2
input.valueAsNumber - Brak pomocy, ponieważ działa to tylko z kropkami jako separatorem dziesiętnym, aw moim przypadku użytkownik końcowy może użyć kropki lub przecinka. Form tag novalidate - Nie znalazłem na to żadnego wpływu.
devha
Niestety brakuje mi pomysłów, więc nie jestem pewien, czy możesz sprawić, by ta działała w różnych przeglądarkach bez rozwiązania obejścia. Zaktualizowałem moją odpowiedź, aby zawierała atrybut wzorca, który również znalazłem, można użyć atrybutu formnovalidate bezpośrednio w polach wejściowych. Wiem, że to nie spodoba, ale jeśli wszystko zawiedzie i koniecznie musisz przecinki następnie wejściowy = „tekst” może być jedynym sposobem ..
kjetilh
Wygląda na to, że numer typu danych wejściowych generuje więcej problemów niż w rzeczywistości poprawia wrażenia użytkownika. W urządzeniu mobilnym byłoby wspaniale, gdybym mógł otworzyć użytkownikowi tylko klawiaturę numeryczną, jeśli chcę, aby wprowadzał tylko liczby. W każdym razie muszę to jeszcze raz przemyśleć ...
devha
Ponieważ musimy również obsługiwać używanie kropek i przecinków jako separatorów dziesiętnych, planujemy użyć wzorca do walidacji na komputerach stacjonarnych w połączeniu z type = "text". Następnie dodamy wykrywanie funkcji do wykrywania urządzenia mobilnego i użyjemy type = "number", gdy ma to zastosowanie.
awe
9

To, czy użyć przecinka, czy kropki jako separatora dziesiętnego, zależy wyłącznie od przeglądarki. Przeglądarka podejmuje decyzję na podstawie ustawień regionalnych systemu operacyjnego lub przeglądarki, albo niektóre przeglądarki pobierają wskazówki z witryny. Zrobiłem tabelę porównawczą przeglądarek pokazującą, jak różne przeglądarki obsługują różne metody lokalizacji. Safari to jedyna przeglądarka, która zamiennie obsługuje przecinki i kropki.

Zasadniczo jako autor stron internetowych nie możesz tego kontrolować. Niektóre obejścia obejmują użycie dwóch pól wejściowych z liczbami całkowitymi. Dzięki temu każdy użytkownik może wprowadzić dane zgodnie z oczekiwaniami. Nie jest to szczególnie seksowne, ale sprawdzi się w każdym przypadku dla wszystkich użytkowników.

Aeyoun
źródło
7

Użyj valueAsNumberzamiast .val().

Wejście . valueAsNumber [= wartość]

Zwraca liczbę reprezentującą wartość kontrolki formularza, jeśli ma to zastosowanie; w przeciwnym razie zwraca null.
Można ustawić, aby zmienić wartość.
Zgłasza wyjątek INVALID_STATE_ERR, jeśli formant nie jest oparty na dacie lub godzinie ani nie jest liczbowy.

Mike Samuel
źródło
2
Problem polega na tym, że chce on obsługiwać przecinek jako separator dziesiętny, a używanie type = "number" na wejściu zawsze podaje nieprawidłową liczbę podczas pisania przecinka.
awe
Wydaje się, że nie działa konsekwentnie na Windows Phone; zawsze wraca NaN.
bert bruynooghe
@bertbruynooghe, co przypisujesz jako wartość?
Mike Samuel
Wydaje się, że nie działa, również z „9”, „9,1”, „9.1”. Telefon jest skonfigurowany jako USA, układy klawiatury przetestowano w wersji en-US, nl-BE.
bert bruynooghe
4

Nie znalazłem idealnego rozwiązania, ale najlepsze, co mogłem zrobić, to użyć type = "tel" i wyłączyć walidację html5 (formnovalidate):

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

Jeśli użytkownik wstawi przecinek, wyświetli się on z przecinkiem w każdej nowoczesnej przeglądarce, którą wypróbowałem (najnowsza FF, IE, edge, opera, chrome, safari desktop, android chrome).

Główny problem to:

  • Użytkownicy telefonów komórkowych zobaczą klawiaturę telefonu, która może być inna niż klawiatura numeryczna.
  • Co gorsza, klawiatura telefonu może nawet nie mieć klawisza na przecinek.

W moim przypadku musiałem tylko:

  • Wyświetl wartość początkową z przecinkiem (Firefox usuwa ją dla type = number)
  • Niepowodzenie weryfikacji html5 (jeśli jest przecinek)
  • Niech pole będzie czytane dokładnie jako dane wejściowe (z możliwym przecinkiem)

Jeśli masz podobne wymagania, powinno to działać dla Ciebie.

Uwaga: nie podobało mi się wsparcie dla atrybutu pattern. Formnovalidate wydaje się działać znacznie lepiej.

Bolo
źródło
4

używa typu tekstowego, ale wymusza wygląd klawiatury numerycznej

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

rozwiązaniem jest tag inputmode

David Navarro
źródło
Ale nie jest kompatybilny ze wszystkimi przeglądarkami, tylko z najnowszymi wersjami iOS Safari, Chrome, Chromium, Opera ... caniuse.com/#feat=input-inputmode :(
pgarciacamou
A dodatkowo nie masz tej schludnej klawiatury numerycznej na urządzeniach mobilnych.
WoIIe,
1

Po wywołaniu $("#my_input").val();zwraca jako zmienną łańcuchową. Więc używaj parseFloati parseIntdo konwersji. Kiedy używasz parseFloatswojego komputera stacjonarnego lub telefonu SAMEGO rozumie znaczenie zmiennej.

Ponadto możesz przekonwertować zmiennoprzecinkowy na ciąg, używając toFixedargumentu, który ma liczbę cyfr, jak poniżej:

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

źródło
Nie działa. Spróbuj parseFloat ("1,5") w IE11. Zwroty 1. Język jest niemiecki dla systemu operacyjnego i przeglądarki IE.
T3rm1
1

Wygląda na to, że przeglądarki nadal mają problemy (chociaż Chrome i Firefox Nightly radzą sobie dobrze). Mam hakerskie podejście do ludzi, którzy naprawdę muszą używać pól liczbowych (może z powodu małych strzałek, których nie mają pola tekstowe).

Moje rozwiązanie

Dodałem obsługę keyupzdarzeń do danych wejściowych formularza i prześledziłem stan i ustawiłem wartość, gdy stanie się znowu ważna.

Czysty fragment kodu JS JSFIDDLE

Angular 9 Snippet

Joniras
źródło
0

Moja rekomendacja? W ogóle nie używaj jQuery. Miałem ten sam problem co ty. znalazłem to$('#my_input').val() zawsze zwraca jakiś dziwny wynik.

Spróbuj użyć document.getElementById('my_input').valueAsNumberzamiast, $("#my_input").val();a następnie użyjNumber(your_value_retrieved) aby spróbować utworzyć liczbę. Jeśli wartość to NaN, z pewnością wiesz, że to nie jest liczba.

Jedną rzeczą do dodania jest wpisanie liczby na wejściu, wejście faktycznie przyjmie prawie każdy znak (mogę napisać znak euro, dolara i wszystkie inne znaki specjalne), więc najlepiej jest pobrać wartość za pomocą .valueAsNumberzamiast używać jQuery.

Aha, i przy okazji, to pozwala Twoim użytkownikom dodawać internacjonalizację (tj: obsługuj przecinki zamiast kropek, aby tworzyć liczby dziesiętne). Po prostu pozwól Number()obiektowi stworzyć coś dla Ciebie, a będzie to, że tak powiem, bezpieczne dziesiętne.

Patrick D'appollonio
źródło
Problem nie jest spowodowany przez jQuery i uważam, że valueAsNumberrównież nie działa konsekwentnie w przeglądarkach.
bert bruynooghe
0

Wygląda na to, że chcesz użyć metody toLocaleString () na wejściach numerycznych.

Zobacz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString, aby zobaczyć jego użycie.

Lokalizacja liczb w JS jest również objęta umiędzynarodowieniem (formatowanie liczb „num.toLocaleString ()”) nie działa w przeglądarce Chrome

stackasec
źródło
2
Zwykle podaje się więcej wyjaśnień na temat rozwiązania, nawet jeśli odpowiedź jest w pełni objęta linkami.
IvanH
To podejście wydaje się być lepsze niż inne, jeśli serwer zaplecza określa ustawienia regionalne, a nie samą przeglądarkę. Niestety, toLocaleStringnie jest niezawodny na różnych platformach.
bert bruynooghe
Obsługa wielu platform wydaje mi się wystarczająco szeroka w 2015 roku, zobacz np. Mozillas Devnet . Jeśli jednak nadal Cię to niepokoi, znajdź tutaj możliwe rozwiązania.
stackasec
Mozillas Devnet prawie nie jest kompatybilny z przeglądarkami mobilnymi i właśnie tam numeryczne pole tekstowe może zaoferować najwięcej korzyści. (Zobacz oryginalne pytanie.)
bert bruynooghe
... i więcej niż wystarczająco alternatyw zostało pokazanych i odniesionych. Baw się dobrze.
stackasec