Как обрабатывать числа с плавающей запятой и десятичные разделители с номером типа ввода html5

128

Я создаю веб-приложение, которое в основном предназначено для мобильных браузеров. Я использую поля ввода с числовым типом, поэтому (большинство) мобильных браузеров вызывает только цифровую клавиатуру для лучшего взаимодействия с пользователем. Это веб-приложение в основном используется в регионах, где десятичным разделителем является запятая, а не точка, поэтому мне нужно обрабатывать оба десятичных разделителя.

Как покрыть весь этот беспорядок точкой и запятой?

Мои выводы:

Настольный Chrome

  • Тип ввода = число
  • Пользователь вводит "4,55" в поле ввода.
  • $("#my_input").val(); возвращает "455"
  • Я не могу получить правильное значение из ввода

Настольный Firefox

  • Тип ввода = число
  • Пользователь вводит "4,55" в поле ввода.
  • $("#my_input").val(); возвращает "4,55"
  • Хорошо, я могу заменить запятую на точку и получить правильное число с плавающей запятой

Браузер Android

  • Тип ввода = число
  • Пользователь вводит "4,55" в поле ввода.
  • Когда ввод теряет фокус, значение усекается до "4".
  • Запутывает пользователя

Windows Phone 8

  • Тип ввода = число
  • Пользователь вводит "4,55" в поле ввода.
  • $("#my_input").val(); возвращает "4,55"
  • Хорошо, я могу заменить запятую на точку и получить правильное число с плавающей запятой

Каковы «лучшие практики» в таких ситуациях, когда пользователь может использовать запятую или точку в качестве десятичного разделителя, а я хочу сохранить тип ввода html как число, чтобы улучшить взаимодействие с пользователем?

Могу ли я преобразовать запятую в точку «на лету», привязав ключевые события, работает ли он с числовым вводом?

РЕДАКТИРОВАТЬ

Currenlty У меня нет решения, как получить значение с плавающей запятой (как строку или число) из ввода, тип которого установлен на число. Если конечный пользователь вводит «4,55», Chrome всегда возвращает «455», Firefox возвращает «4,55», что нормально.

Также весьма раздражает то, что в Android (проверенный эмулятор 4.2), когда я ввожу «4,55» в поле ввода и меняю фокус на другое место, введенное число обрезается до «4».

devha
источник
Я предполагаю, что основная причина некоторых из ваших проблем заключается в том, что браузеры настроены на региональный стандарт США, который использует точку в качестве десятичного разделителя. Кажется, что Chrome и Android по-разному запутались в этом: Chrome обрабатывает запятую как разделитель цифр, затем преобразует ввод в число, затем снова преобразует его в строку .val(), а Android делает что-то странное. Можете ли вы проверить, ведут ли они себя так же, когда вы устанавливаете язык системы на что-нибудь подходящее?
millimoose 08
1
Nvm опубликовал это в качестве ответа
kjetilh
См. Также здесь: stackoverflow.com/a/24423879/196210
Предыдущий 03
Ситуация даже хуже, чем вы изобразили: вы получаете десятичную точку или запятую на цифровой клавиатуре WP в зависимости от языка, на котором вы выбрали клавиатуру для работы. Также нет способа узнать, какой был языковой стандарт ввода (не обязательно предпочтительный язык браузера) ... Итак, лучшее, что я мог придумать (и что мне подходит), это: var number = $(...).get(0).valueAsNumber; if (isNaN(number)) number = parseFloat($(...).val().replace(',', '.'); Но это решение работает только в том случае, если число, которое было введено, содержит только 1 запятую и без лишних точек ...
Берт Брюноог

Ответы:

107

Я думаю, что в приведенных выше ответах не хватает необходимости указать другое значение для stepатрибута, значение которого по умолчанию равно 1. Если вы хотите, чтобы алгоритм проверки входных данных допускал значения с плавающей запятой, укажите соответствующий шаг.

Например, мне нужны долларовые суммы, поэтому я указал следующий шаг:

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

Нет ничего плохого в использовании jQuery для получения значения, но вы сочтете полезным напрямую использовать DOM API для получения validity.validсвойства элементов .

У меня была аналогичная проблема с десятичной точкой, но я понял, что проблема возникла из-за стиля, который Twitter Bootstrap добавляет к числовому вводу с недопустимым значением.

Вот скрипка, демонстрирующая, что добавление stepатрибута заставляет его работать, а также проверка, действительно ли текущее значение:

TL; DR: установите для stepатрибута a значение с плавающей запятой, поскольку по умолчанию оно равно 1.

ПРИМЕЧАНИЕ . Запятая меня не проверяет, но я подозреваю, что если я установлю в настройках языка / региона моей ОС значение, в котором в качестве десятичного разделителя используется запятая, это сработает. * примечание в примечании *: этого не было для языка ОС / настроек клавиатуры * Немецкий * в Ubuntu / Gnome 14.04.

natchiketa
источник
8
Если вы хотите разрешить произвольное количество десятичных знаков, укажите stepатрибут as "any"вместо, например, "0.01"как показано здесь. См. Эту измененную версию скрипки nathciketa для демонстрации.
Марк Эмери
4
Я также столкнулся с проблемами, когда запятые не проверялись, хотя я вводил «1,234,56» <input type="number" step="any">. Мне не удалось найти способ отключить проверку HTML5. Я могу отключить или настроить сообщение об ошибке, но получение значения из входных данных всегда является чушью. Любые идеи?
Ник Г.
5
This attribute applies when the value of the type attribute is text, search, tel, url, email, or password, otherwise it is ignored.Так что шаблон бесполезен сtype="number"
Майкл
как сказал Майкл, пожалуйста, измените значение typeна text, иначе ваш ответ не имеет смысла.
phil294
23

Согласно w3.org атрибут value ввода числа определяется как число с плавающей запятой. . Синтаксис числа с плавающей запятой, кажется, принимает только точки в качестве десятичных разделителей.

Ниже я перечислил несколько вариантов, которые могут быть вам полезны:

1. Использование атрибута pattern

С помощью атрибута pattern вы можете указать разрешенный формат с помощью регулярного выражения совместимым с HTML5 способом. Здесь вы можете указать, что символ запятой разрешен, и полезное сообщение обратной связи, если шаблон не работает.

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

Примечание: кроссбраузерная поддержка сильно различается. Он может быть полным, частичным или отсутствовать.

2. Проверка JavaScript

Вы можете попробовать привязать простой обратный вызов, например, к onchange (и / или размыть ), которое либо заменит запятую, либо подтвердит все вместе.

3. Отключить проверку браузера ##

В-третьих, вы можете попробовать использовать атрибут formnovalidate для числовых входов, чтобы полностью отключить проверку браузера для этого поля.

<input type="number" formnovalidate />

4. Комбинация ..?

<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
источник
2
input.valueAsNumber - Никакой помощи, поскольку это работает только с точками в качестве десятичного разделителя, и в моем случае конечный пользователь может использовать точку или запятую. Form tag novalidate - не обнаружил никакого влияния на это.
devha 09
К сожалению, у меня заканчиваются идеи, поэтому я не уверен, что вы сможете сделать эту работу кросс-браузерной без обходного решения. Я обновил свой ответ, включив в него атрибут шаблона. Я также обнаружил, что можно использовать атрибут formnovalidate непосредственно в полях ввода. Я знаю, вам это не понравится, но если что-то не так и вам абсолютно необходимы запятые, тогда input = "text" может быть единственным выходом ..
kjetilh
Похоже, что номер типа ввода создает больше проблем, чем на самом деле улучшает взаимодействие с пользователем. На мобильном устройстве было бы здорово, если бы я мог открывать пользователю только цифровую клавиатуру, если я хочу, чтобы они вводили только числа. В любом случае, мне нужно еще раз обдумать это ...
Девха
Поскольку нам также необходимо поддерживать использование точки и запятой в качестве десятичного разделителя, мы планируем использовать шаблон для проверки на рабочем столе в сочетании с type = "text". Затем мы добавим функцию обнаружения мобильных устройств и будем использовать type = "number", когда это применимо.
awe
9

Использование запятой или точки для десятичного разделителя полностью зависит от браузера. Браузер принимает решение в зависимости от языкового стандарта операционной системы или браузера, или некоторые браузеры получают подсказки с веб-сайта. Я составил сравнительную таблицу браузеров, показывающую, как разные браузеры поддерживают разные методы локализации. Safari - единственный браузер, в котором запятые и точки взаимозаменяемы.

По сути, вы, как веб-автор, не можете это контролировать. Некоторые обходные пути включают использование двух полей ввода с целыми числами. Это позволяет каждому пользователю вводить данные так, как вы ожидаете. Это не особо привлекательно, но будет работать в любом случае для всех пользователей.

Aeyoun
источник
7

Используйте valueAsNumberвместо .val().

ввод. valueAsNumber [= значение]

Возвращает число, представляющее значение элемента управления формы, если применимо; в противном случае возвращает null.
Можно установить, чтобы изменить значение.
Выдает исключение INVALID_STATE_ERR, если элемент управления не является ни датой, ни временем, ни числовым.

Майк Сэмюэл
источник
2
Проблема в том, что он хочет поддерживать запятую в качестве десятичного разделителя, а использование type = "number" на входе всегда дает недопустимый номер при записи запятой.
awe
Кажется, не работает стабильно на Windows Phone; всегда возвращается NaN.
Берт Брюнооге
@bertbruynooghe, что вы ставите в качестве значения?
Майк Сэмюэл
Похоже, не работает ни с «9», «9,1», «9.1». Телефон настроен как US, раскладки клавиатуры проверены en-US, nl-BE.
Берт Брюнооге
4

использует текстовый тип, но принудительно отображает цифровую клавиатуру

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

тег inputmode - это решение

Давид Наварро
источник
Но он совместим не со всеми браузерами, только с последними версиями iOS Safari, Chrome, Chromium, Opera ... caniuse.com/#feat=input-inputmode :(
pgarciacamou
И, кроме того, вы не получите эту аккуратную цифровую клавиатуру на мобильных устройствах.
WoIIe
3

Я не нашел идеального решения, но лучшее, что я мог сделать, это использовать type = "tel" и отключить проверку html5 (formnovalidate):

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

Если пользователь поставит запятую, он будет выводить с запятой в каждом современном браузере, который я пробовал (последний FF, IE, edge, opera, chrome, рабочий стол Safari, android chrome).

Основная проблема:

  • Пользователи мобильных устройств увидят клавиатуру своего телефона, которая может отличаться от цифровой.
  • Хуже того, на клавиатуре телефона может даже не быть клавиши для запятой.

Для моего варианта использования мне нужно было только:

  • Отобразите начальное значение через запятую (firefox удаляет его для type = number)
  • Не провалить проверку html5 (если есть запятая)
  • Считайте поле точно так же, как ввод (с возможной запятой)

Если у вас есть подобное требование, это должно сработать для вас.

Примечание: мне не понравилась поддержка атрибута pattern. Formnovalidate, кажется, работает намного лучше.

Боло
источник
1

Когда вы вызываете, $("#my_input").val();он возвращается как строковая переменная. Так что используйте parseFloatи parseIntдля конвертации. Когда вы используете parseFloatсвой компьютер или телефон, САМ понимает значение переменной.

И, кроме того, вы можете преобразовать число с плавающей запятой в строку, используя toFixedаргумент, который имеет количество цифр, как показано ниже:

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

источник
Не работает. Попробуйте parseFloat ("1,5") в IE11. Возврат 1. Языком для ОС и IE является немецкий.
T3rm1
1

Судя по всему, у браузеров все еще есть проблемы (хотя Chrome и Firefox Nightly все в порядке). У меня есть хитрый подход для людей, которым действительно нужно использовать числовое поле (возможно, из-за маленьких стрелок, которых нет в текстовых полях).

Мое решение

Я добавил keyupобработчик событий к вводу формы, отслеживал состояние и устанавливал значение, когда оно снова становится действительным.

Чистый фрагмент кода JS JSFIDDLE

Угловой 9 фрагмент

Joniras
источник
0

Моя рекомендация? Не используйте jQuery вообще. У меня была такая же проблема, как и у вас. Я обнаружил, что $('#my_input').val()всегда возвращает какой-то странный результат.

Попробуйте использовать document.getElementById('my_input').valueAsNumberвместо, $("#my_input").val();а затем используйте, Number(your_value_retrieved)чтобы попытаться создать число. Если значение равно NaN, вы точно знаете, что это не число.

Следует добавить, что когда вы пишете число на входе, ввод фактически принимает почти любой символ (я могу написать знак евро, доллар и все другие специальные символы), поэтому лучше всего получить значение, используя .valueAsNumberвместо использования jQuery.

Да, и кстати, это позволяет вашим пользователям добавлять интернационализацию (то есть: поддерживать запятые вместо точек для создания десятичных чисел). Просто позвольте Number()объекту создать что-то для вас, и это будет, так сказать, безопасно для десятичных чисел.

Патрик Д'Апполлонио
источник
Проблема не вызвана jQuery, и я считаю, что valueAsNumberон также не работает последовательно в браузерах.
Берт Брюнооге
0

Похоже, вы хотели бы использовать toLocaleString () для числовых входов.

См. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString для его использования.

Локализация чисел в JS также рассматривается в разделе "Интернационализация" (форматирование чисел "num.toLocaleString ()"), не работающем для Chrome.

stackasec
источник
2
Обычно дается более подробное объяснение решения, даже если ответ полностью покрыт ссылками.
IvanH
Этот подход кажется лучше, чем другие подходы, если внутренний сервер определяет локаль, а не сам браузер. К сожалению, toLocaleStringэто ненадежно для разных платформ.
Берт Брюнооге
Кросс-платформенная поддержка мне кажется достаточно широкой в ​​2015 году, см., Например, Mozillas Devnet . Однако, если вас это все еще беспокоит, найдите здесь возможные решения.
stackasec
Mozillas Devnet почти не поддерживает совместимость с мобильными браузерами, и именно здесь числовое текстовое поле может дать наибольшие преимущества. (См. Исходный вопрос.)
Берт Брюноог
... и было показано более чем достаточно альтернатив. Радоваться, веселиться.
stackasec