Справился я с заданием достаточно быстро, повесив на input событие focusout, но у моего решения был ряд важных недостатков: где в данном примере заканчивается сумма в рублях и начинаются копейки? Если пользователь введет несколько минуcов (отрицательные значения тоже корректны в данном случае), то какой из минусов считать началом строки? И так далее.
Поэтому появилась вторая версия скрипта с регулярными выражениями на событие keyup:
$(e.curretTarget).val(($(e.currentTarget).val()).replace( /[^0123456789.-]/, '' ))
Но как оказалось, этот способ имел ощутимый недостаток (я не имею ввиду то, что пользователь видит символ, который вводит и потом этот символ пропадает), а именно — если поставить курсор, например, посередине введенного числа в input, ввести букву, то скрипт вырежет букву, но перекинет курсов в конец строки.
По этой причине старший товарищ дал указание написать функцию на событие keypress. Через 30 минут уже третий вариант функции был готов и имел он примерно такой вид:
function()
{
return this.each(function()
{
$(this).keydown(function(e)
{
var key = e.charCode || e.keyCode || 0;
// allow backspace, tab, delete, enter, arrows, numbers and keypad numbers ONLY
// home, end, period, and numpad decimal
return (
key == 8 ||
key == 9 ||
key == 13 ||
key == 46 ||
key == 110 ||
key == 190 ||
(key >= 35 && key <= 40) ||
(key >= 48 && key <= 57) ||
(key >= 96 && key <= 105));
});
});
};
Код взят со steckoverflow, но мой код мало чем отличался от примера выше.
Всё выглядело красиво — пользователь не видит вводимых чисел и курсор не перебрасывает в конец строки, но, как оказалось, радовались мы рано. Если смотреть на keycode клавиш на разных операционных системах (mac, linux, win), то они имеют некоторые различия, а если к этому прибавить то, что не у всех маков есть numPud и, следовательно, числа вводятся с зажатым шифтом и также цифры могут вводится с виртуальной клавиатуры. В итоге получается код во много раз больше, чем последний пример.
В итоге я написал скрипт на событие keyup и он заработал с единственным недостатком — пользователь на секунду видит вводимое число. По понятным причинам я не могу выложить скрипт, но эта ситуация побудила меня написать новый скрипт, который я выложил на github. Я сделал скрипт более универсальным — сейчас он больше рассчитан на передачу значения в DOM-элементы, чем на модификацию введенного значения в input (это будет следующий шаг).
На момент написания статьи в функцию можно передать несколько параметров:
- forDisplay: true, // для отображения в дивах
- classOfDomElement: '',// классы DOM элементов через запятую без пробелов
- idOfDomElement: '',// id DOM элементов через запятую без пробелов
- //forInput: false,
- forSave: false, // function forSave — возвращает только цифры с точкой
- negative: false,
- afterPoint: 2, // количество цифр после точки
- showPoint: true, // показывать точку до ввода копеек
- currency: 'руб.' // валюта
Спасибо за внимание!
Комментарии (27)
Delphinum
17.10.2016 16:09-2По этой причине старший товарищ дал указание написать функцию на событие keypress
А старший товарищ не дал линейкой по рукам и не предложил готовое решение, коих в интернете пачка?
Nadoedalo
17.10.2016 16:33-4jsfiddle, тесты — это раз
ужасный английский в readme — это два
ужасная организация кода — это три
PS собственно сам денежный формат с кучей фич влезает в 27 строчек кода(на 12 кейсов) + «обёрточная мишура» на 25 строк + сеттер/геттер позиции курсора(необходимо только для FF, возможно уже и пофикшено). Выложить код к сожалению не могу, но однозначно есть способ сделать это лучше.
PSS далеко ушли от собственно говоря реализации денежного формата. В идеале это две функции «на выход» — одна собственно которая превращает строку в денежный формат, другая — умеет превращать DOM-элементы в тип денежного формата.tarasikgoga
17.10.2016 17:04+4ужасная организация кода — это три
буду рад если подскажите как организовать код лучшеNadoedalo
17.10.2016 18:47-6Дай человеку рыбу и он будет сыт один день…
Посмотрите что-ли курсы в интернете, попишите например на Vanilla JS framework(или на любой другой устоявшейся либе/фреймворке). Да хотя бы гляньте на код TODO app'a.
Просто бесполезно объяснять что не так с кодом. Это приходит со временем или вообще не приходит.
AlexPu
17.10.2016 16:42Я припоминаю, что делал нечто подобное и именно с использованием keydown. никаких проблем с маками не имел (несколько разработчиков и практически все менеджеры были вооружены именно ими). Более того, я не просто фильтровал вводимые символы но и попутно их форматировал — все нормально было… помню, что код чамому очень понравился, что для меня очень редкое явление… но… не сберег… я вообще пофигистично отношусть к своему, да и к чужому коду… надо будет — еще напишу…
bacsus_beacks
17.10.2016 17:54-1<input type='number' step='0.01'>
And everybody is happy.
Nah?Nadoedalo
17.10.2016 18:55-4Как и обычно встроенные инпуты работают не идеально с минимальными возможностями исправить поведение. Понятно что нативные элементы работают _лучше_(в широком смысле этого слова, например в разных окружениях), но не всегда так как хотелось бы. Лично мне приходилось писать и textarea и select'ы и эмулировать таблицу div'ами просто потому что так — гибче. Ну и типичный пример — ужасно-некрасивый скролл внутри документа от которого дизайнеры плюются а пользователей коробит.
Вот если бы можно было «внутрь» нативных элементов залезать тогда да(на самом деле уже «можно» с помощью Webcomponents/Shadow root вот этого всего), но пока что — приходится извращаться.
Zavtramen
17.10.2016 17:56+6где в данном примере заканчивается сумма в рублях и начинаются копейки?
В данном примере нигде. Введенная строка не является валидной суммой и об этом должно быть сообщено пользователю.
cjbars
17.10.2016 18:21+7Я может быть глупость спрошу, но зачем все эти переподвыпернверты? Выше написали поо input type number, а обо всем остальном надо оповестить пользователя. Если вы хотите чистить данные перед отправкой их на сервер, то мне кажется это глупо, ибо данные можно отправить и без инпутов.
muxa_ru
17.10.2016 22:00Не знаю зачем оно нужно, но для полноты функционала нужно обрабатывать и то что из буфера вставляется.
Shannon
18.10.2016 02:18По этой причине старший товарищ дал указание написать функцию на событие keypress.
…
Код взят со steckoverflow, но мой код мало чем отличался от примера выше.
…
Всё выглядело красиво — пользователь не видит вводимых чисел и курсор не перебрасывает в конец строки, но, как оказалось, радовались мы рано. Если смотреть на keycode клавиш на разных операционных системах (mac, linux, win), то они имеют некоторые различия, а если к этому прибавить то, что не у всех маков есть numPud и, следовательно, числа вводятся с зажатым шифтом и также цифры могут вводится с виртуальной клавиатуры. В итоге получается код во много раз больше, чем последний пример.
Разница есть. Ваш товарищ дал вам указание использовать keypress, а в примере keydown, в этом и есть разница
У keypress будет код финального символа, а у keydown будет выдан keyCode клавиши плюс флаги нажат ли shift, alt и т.д, раскладка игнорируется. Можно проверить в живую: https://learn.javascript.ru/keyboard-events
То есть если у нас keypress и нажать 1 мы получим keyCode=49, с зажатым шифтов получим уже keyCode=33
Если у нас keydown и нажать 1 (хоть с шифтом, хоть с чем угодно) мы всегда получим keyCode=49 на любой клавиатуре, на любой ОС, хоть на виртуальной клавиатуре планшета
Аналогично даже если текущая раскладка русская, нажимая точку получаем 'ю', но keyCode всё равно будет 190 (как и у просто точки), а не 1102 (код символа 'ю')
dkameleon
18.10.2016 08:21+2Не надо изобретать костыли и решать за пользователя, что он хотел ввести.
Хотите ограничить его в отправке неправильных данных — type=number + pattern
Велосипед focusout не едет в ФФ.
Если смотреть на keycode клавиш на разных операционных системах (mac, linux, win), то они имеют некоторые различия, а если к этому прибавить то, что не у всех маков есть numPud и, следовательно, числа вводятся с зажатым шифтом и также цифры могут вводится с виртуальной клавиатуры. В итоге получается код во много раз больше, чем последний пример.
А завтра выпустят новый модный молодежный браузер и вам опять перепроверять и переписывать костыли.tarasikgoga
18.10.2016 08:27Велосипед focusout не едет в ФФ.
Не знаю про какой вы велосипед, но мой код работает в ФФ.
RubaXa
18.10.2016 11:31Зачем это всё? Уже много лет есть куча готовых и проверенных решений для jQuery.
RoseWoodsAlloy
18.10.2016 12:23Занимательная статья.
Занимательно в ней все. Особенно меня впечатлили steckoverflow и numPud…
… Представляете… целый пуд нумов в английском переполнении немецкого штекера.
Taller
18.10.2016 17:541,234.5
1234.501
1.234,50
1234,5
1234-50
а такие суммы одинаковы или нет? =)
В свое время решал подобную задачу на Java и это был основной вид сумм в документах от разных бухгалтерий, которые приходилось распознавать. Были и другие, менее популярные.
Zhuravljov
19.10.2016 06:49Получил я достаточно стандартное задание: фильтровать вводимые юзером символы в input
Задание то стандартное, но подошли вы к нему не с той стороны. Если просто потренироваться — возможно. А для реальных приложений так делать не стоит.
Какой смысл распознавать пользовательский бред? Особенно когда он не однозначен. Проще сообщить, что введенное выражение не соответствует. Дальше то все равно последует серверная валидация.
А если и нужны ограничения на этапе ввода, то проще
type="number"
или атрибутpattern
.
LakeVostok
19.10.2016 08:26простая функция фильтра инпута от букв, т.е. вводивые буквы не появляются в инпуте. Вешается на oninput
function(){
event.target.value = event.target.value.replace(/[^0-9\.]/g,'');
});
http://codepen.io/vasyatopor/pen/kkAmZW?editors=1010
Дальше сами модернизируйтеtarasikgoga
19.10.2016 08:27Если ввести 5555, а потом ввести букыу вот так 55а55, букву вырежит а курсор перекинет в конец строки
cjbars
19.10.2016 15:50А если ввести 5e3 рублей?
Ведь это верная запись = 5000 рублей
Что прикажете делать с этим?
Dolios
Для тестового задания пойдет, а в жизни такой подход применять крайне опасно. Что если ваша 't', это опечатка, при попытке нажать '6'?