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”.
.val()
, a Android robi coś dziwnego. Czy możesz sprawdzić, czy zachowują się tak samo, gdy ustawisz język systemu na coś odpowiedniego?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 ...Odpowiedzi:
Myślę, że w powyższych odpowiedziach brakuje konieczności określenia innej wartości
step
atrybutu, 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
step
atrybutu sprawia, że działa, a także testujące, czy bieżąca wartość jest prawidłowa:TL; DR: Ustaw
step
atrybut a na wartość zmiennoprzecinkową, ponieważ domyślnie1
.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.
źródło
step
atrybut jako"any"
zamiast np."0.01"
Jak pokazano tutaj. Zobacz tę ulepszoną wersję skrzypiec nathciketa, aby zobaczyć demo.<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?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"
type
siętext
, w przeciwnym razie odpowiedź nie mają żadnego sensu.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."/>
źródło
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.
źródło
Użyj
valueAsNumber
zamiast.val()
.źródło
NaN
.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:
W moim przypadku musiałem tylko:
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.
źródło
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
źródło
Po wywołaniu
$("#my_input").val();
zwraca jako zmienną łańcuchową. Więc używajparseFloat
iparseInt
do konwersji. Kiedy używaszparseFloat
swojego komputera stacjonarnego lub telefonu SAMEGO rozumie znaczenie zmiennej.Ponadto możesz przekonwertować zmiennoprzecinkowy na ciąg, używając
toFixed
argumentu, który ma liczbę cyfr, jak poniżej:var i = 0.011; var ss = i.toFixed(2); //It returns 0.01
źródło
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ę
keyup
zdarzeń 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
Pokaż fragment kodu
var currentString = ''; var badState = false; var lastCharacter = null; document.getElementById("field").addEventListener("keyup",($event) => { if ($event.target.value && !$event.target.validity.badInput) { currentString = $event.target.value; } else if ($event.target.validity.badInput) { if (badState && lastCharacter && lastCharacter.match(/[\.,]/) && !isNaN(+$event.key)) { $event.target.value = ((+currentString) + (+$event.key / 10)); badState = false; } else { badState = true; } } document.getElementById("number").textContent = $event.target.value; lastCharacter = $event.key; }); document.getElementById("field").addEventListener("blur",($event) => { if (badState) { $event.target.value = (+currentString); badState = false; document.getElementById("number").textContent = $event.target.value; } });
#result{ padding: 10px; background-color: orange; font-size: 25px; width: 400px; margin-top: 10px; display: inline-block; } #field{ padding: 5px; border-radius: 5px; border: 1px solid grey; width: 400px; }
<input type="number" id="field" keyup="keyUpFunction" step="0.01" placeholder="Field for both comma separators"> <span id="result" > <span >Current value: </span> <span id="number"></span> </span>
Angular 9 Snippet
Pokaż fragment kodu
@Directive({ selector: '[appFloatHelper]' }) export class FloatHelperDirective { private currentString = ''; private badState = false; private lastCharacter: string = null; @HostListener("blur", ['$event']) onBlur(event) { if (this.badState) { this.model.update.emit((+this.currentString)); this.badState = false; } } constructor(private renderer: Renderer2, private el: ElementRef, private change: ChangeDetectorRef, private zone: NgZone, private model: NgModel) { this.renderer.listen(this.el.nativeElement, 'keyup', (e: KeyboardEvent) => { if (el.nativeElement.value && !el.nativeElement.validity.badInput) { this.currentString = el.nativeElement.value; } else if (el.nativeElement.validity.badInput) { if (this.badState && this.lastCharacter && this.lastCharacter.match(/[\.,]/) && !isNaN(+e.key)) { model.update.emit((+this.currentString) + (+e.key / 10)); el.nativeElement.value = (+this.currentString) + (+e.key / 10); this.badState = false; } else { this.badState = true; } } this.lastCharacter = e.key; }); } }
<input type="number" matInput placeholder="Field for both comma separators" appFloatHelper [(ngModel)]="numberModel">
źródło
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').valueAsNumber
zamiast,$("#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ą
.valueAsNumber
zamiast 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.źródło
valueAsNumber
również nie działa konsekwentnie w przeglądarkach.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
źródło
toLocaleString
nie jest niezawodny na różnych platformach.