23 июля 2012 в 15:45

Как сделать группу инпутов удобной

Когда я работал над сервисом заметок jotsky.com, еще до работы в Островке, надо было сделать ввод телефонного номера из двух инпутов. Примерно такой:



Я сделал навигацию с помощью стрелочек. Сделал, чтобы по мере заполнения фокус переключался к следующем инпуту. А вот сделать правильную вставку из буфера обмена у меня никак не получалось.

Вставку из буфера можно реализовать установив атрибут maxlength с запасом. Для кода города его значение должно быть минимум длины телефонного номера, то есть не три, а десять.

Проблема была даже не в том, чтобы между цифрами вставить еще цифры. А в том, что если зажать кнопку с клавиатуры и не отжимать, то поведение получалось очень странным: вначале заполняется один инпут на весь maxlength, потом пользователь отжимает клавишу и получает мерцание из-за того, что цифры распределяются по остальным инпутам.

К слову, это был 2008 год, и единственная возможность, которую я видел, было спрограммировать все через setTimeout. Предвидя время разработки и неудовлетворительный результат, мы объединили эту форму в одну, которая дожила без изменений до наших дней.

Прошли годы. Браузеры реализовали событие oninput. Сообщество популизировало событие onpropertychange в IE. А передо мной, уже в Островке, встала задача реализовать вставку из буфера обмена номера кредитной карты и заодно для поля срока ее действия.



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

Встречайте jQuery Group Inputs — плагин для группировки инпутов.

Инпуты начинают вести себя будто у них общие данные:
— Когда место заканчивается, каретка перемещается дальше
— Кнопки вправо/влево перебрасывают каретку в следующий/предыдущий инпут
— Вставка текста разбрасывает текст по инпутам, после вставки курсор встает так, как-будто это один инпут.

Пример использования:
<script src="jquery-1.7.2.js"></script>
<script src="jquery.groupinputs.js"></script>
<input type="text" maxlength="4" class="group1" name="">
<input type="text" maxlength="4" class="group1" name="">
<input type="text" maxlength="4" class="group1" name="">
<input type="text" maxlength="4" class="group1" name="">
<script>
     $('.group1').groupinputs();
</script>


Репозиторий на GitHub.
Демо.

Автор: lusever
Автор: @Ostrovok
Ostrovok.ru
рейтинг 46,15
Компания прекратила активность на сайте
Похожие публикации

Комментарии (98)

  • +9
    Огромное спасибо
    • 0
      эээм… opera 11.64 Win XP. Копирую пример — не работает =)
      • 0
        Дык нет еще одного плагина. курсорс.чего-то там.
        Смотрите в демо, на гите.

        Кстати сделать бы опшн для замены не-цифр (при вводе телефона/карты с пробелами-черточками полезно)
      • 0
        Не уверен насчет версии 11, но в 12 сделал.
    • 0
      Да, да, Вилен, вот так это делается. Куча тестов, тщательный подбор событий, пробы, ошибки, правки… Годы работы. А не «а не зафигарить ли нам такую фичу!?».
  • +3
    Example -> выделить -> Ctrl + V в поле с первым инпутом, (неотпуская crtl с прошлого раза) CTRL + Z
    Если в первый импут вставить и попытаться нажать CTRL + A (я так всегда делаю, чтоб выделить и заменить) — то перескакиваем на второй импут, ещё до нажатия на A

    Как то по мне не удобненько
    • 0
      Второй пункт с CTRL+A срабатывает, если курсором ткнуть в конец текста в инпуте.
    • 0
      А в «Credit Card Example» такой баг не наблюдается.
      • +1
        Прошу прощения, наблюдается, но при специфических условиях, см. выше.
    • +1
      +Delete не работает между инпутами. Chrome 20 (омг, еще недавно был 10!), Linux x86.
    • +1
      У меня в хроме и фаерфоксе, если находиться в конце инпута и нажать просто на Ctrl, то перескакивает на следующий инпут. Думаю, это не сложно исправить :-)
      • 0
        Не только Ctrl, любая клавиша перебрасывает (лично у меня). Shift, Alt, Arrow Down, etc.
    • +1
      Спасибо, буду исправлять.
    • 0
      Исправил, спасибо.
  • 0
    Спасибо, удобная вещь. Не планируется ли возможность перезаписи существующих значений полей? Пример: заполнили все поля двойками, потом стрелками переместились в первое поле, и зажали тройку. Сейчас просто ничего не произойдет, а было бы здорово иметь возможность заменять текущее значение новым.
    • 0
      Я не планирую. Ниже есть обсуждение плагинов, из которых Masked Input точно умеет делать такое поведение, но для одного инпута.
  • 0
    В примере пробелы съелись.
    • 0
      Исправил, спасибо.
      • 0
        Я сначала подумал что это так и нужно, предположив что jqyery обрабатывает такие инпуты.
  • +19
    Чем не люблю такие поля — никогда не знаешь примет ли оно все значение целиком или придется копировать каждую часть по-отдельности.
    • +4
      Я привык в таких случаях сначала копировать значение целиком, получилось — отлично, сэкономил время; не получилось, ну и ладненько — первое поле заполнилось, остальные придётся по частям.
  • +39
    >> Как сделать группу инпутов удобными
    Отказаться от группы инпутов и сделать один-единственный инпут. Номер карты позволить вводить через дефисы, через пробелы или слитно, код в номере телефона — в скобках, через дефис или через пробел.
    • 0
      Как вариант (можно в ненормальное программирование)
      1 импут, наверстать на нём маленькие дивы вертикальными разделителями, и яваскриптом сделать вставку пробелов через каждые 4 символа.
    • +4
      В jquery кстати есть плагин для ввода по маске, он сам разбивает текст по заданному шаблону, вставляет недостающие символы, вырезает лишние и вообще довольно умный + корректно работает с историей ввода реализованной как самим браузером так и сторонними плагинами того же jquery
      • 0
        имя, брат, имя?!
        • +1
          сейчас ниже столько плагинов накидают :)
          Надо только подождать, всё интересное в комментах, как всегда.
        • +1
          Да вот коммент написал а сам пошел вспоминать проект где использовал и искать)

          jquery.maskedinput звать

          Выбирал из нескольких, понравился этот. Самое в нем приятное, что служебные символы в маске, которые задаешь сам — например для номера (926) 234-2455 служебными могут быть (___) ___-____
          Эти символы как будто живут «вне» инпута и их нельзя удалить, перенести или вообще как-либо испортить, они всегда будут стоять на своих местах. При этом они нормально копируются вместе с текстом и не мегают вставке и вводу (курсор через них «перепрыгивает»)
          • 0
            Собственно сайт digitalbush.com/projects/masked-input-plugin/

            и там же живые примеры
          • 0
            Почти хороший, кроме того что при фокусе выделяет весь инпут, и в iOS курсор не очень правильно работает.
            • 0
              Выделение инпута при фокусе вполне стандартное поведение, не вижу проблемы в этом?
              • 0
                Это естественно для строки адресной строки браузера, или для поисковой строки. Для полей ввода естественно поставить курсор в место куда кликнули.
                • 0
                  Хмм пожалуй да, согласен. Думаю такое поведение можно «вылечить»
        • 0
          Вот этот плагин на основе маскединпута, но гораздо круче
          github.com/RobinHerbots/jquery.inputmaskhttps://github.com/RobinHerbots/jquery.inputmask
  • +1
    В опере вставка не работает
    • +8
      Вы что, судя по последним тенденциям большинство веб разработчиков вообще оперу за браузер не считают.
      • –1
        <Дядя Миша> У тебя какая-то неправильная Опера, называется Хром. Правильная Опера — это Мозилла.
      • 0
        И слава богу, может тогда ее доля вместе ие упадет
        • +1
          Монополия Хрома — это тоже не очень-то хорошо.
    • 0
      Исправил, проверял в 12ой, спасибо.
  • –1
    А кто-то всё это вводит вручную? Проще сохранить в текстовый файлик или keepass, да копипастить…
    • +13
      > Hacker
      > сохранить в текстовый файлик
      facepalm.jpg
      • +1
        Так он же hacker, вот и советует так, чтобы потом проще ломать было.
    • 0
      Мне кажется, Вы путаете понятия «разработчики» и «целевая аудитория сайта».
  • 0
    Неоднократно нарывался на неприятный момент в таких разделенных инпутах (особенно при установке Windows старых версий), когда глядя то в бумажку, то на клавиатуру пропускаешь один символ или вставляешь лишний. В вашем плагине при удалении символа в середине, правая часть не подтягивается влево. И добавить в середину тоже невозможно.
  • +7
    Есть прекрасный плагин inputmask, который как раз позволяет в пределах одного инпута делать любые разделители. Это гораздо удобнее, чем возиться с энным количеством инпутов (не говоря уже о том, что на сервере это потом в одно значение надо собирать).
    • +2
      Это же стартап, там дух делать свои изобретения ещё не угас.
      А за плагин плюсик, он действительно делает свою работу.
      • +1
        С моего пулл-реквеста там, кстати, русские символы в буквосодержащих масках работают :)
        Так что активно используется в работе.
    • 0
      Мало того собирать на стороне сервера, это потом еще (когда человек захочет, например, отредактировать номер телефона) — обратно надо разбирать все на инпуты.
  • +1
    Мне нравится вот этот плагин. Тут его продолжение. Очень удобно.
  • 0
    Мне всё-таки кажется, при попытке вставить срок годности карты со случайно захваченным пробелом спереди его стоит вычистить.
    • 0
      Более того стоит вообще игнорировать все символы кроме цифр, зачем они нам.
  • 0
    После вставки через ctrl+v, если решишь перезаписать номер вручную, то не стирается предыдущее значение за курсором. Т.е. по моему у таких контролов должен быть что-то вроде replace mode, т.к. сейчас складывается ощущение что вообще readonly пока не выделишь и не удалишь. (chromium + ubuntu x64) последние версии.
  • +1
    ITU-T recommendation E.123 describes how to represent an international telephone number in writing or print, starting with a plus sign ("+") and the country code.

    для кого эти стандарты пишут не понятно, тем более и jotsky.com вы сделали на английском, если б делали для одной страны ладно уже можно было и без "+".

    • 0
      Плюс действительно нужен. Я немного не однозначно написал.
      Картинка примерно иллюстрирует как поле ввода выглядело давно. Сейчас оно выглядит по другому и там есть знак плюса.
  • +1
    А что насчет телефонов то в итоге? Сделали какое-нибудь решение?
    Приведенное решение по очевидным причинам не подходит:

    «Код страны», для русскоговорящей аудитории — +7 либо +375 либо +380 либо многие указывают «8». Т. е. maxlength мне какой ставить? 1, 2, 3 или 4?

    «Код города» — от 3 до 5 цифр, например 495 у Москвы или 83531 у Алатыря
    maxlength 3 или 5?

    Соответственно последнее поле (номер телефона) — от 7 до 5 цифр в зависимости от города.
    maxlength — 7? А если человек хочет указать добавочный (для корп. пользователей например распространенный формат +7 495 123-45-67 (доб. 231)
    • –1
      Для телефонов не подходит.
      Мы остановились на select для кода города и input для продолжения.
  • 0
    надо было сделать ввод телефонного номера из двух инпутов
    А вот интересно, зачем? Почему не одно поле?
    • +3
      Некоторые люди, когда у них спрашивают номер телефона — вводят свой городской номер и не парятся.
      А ты гадай, из какого он города (или вообще — страны, если сайт ориентирован на СНГ)

      Поля «код страны» и «код города» служат напоминанием, что надо указать эти сведения.

      Masked Input и иже с ними — не панацея:
      Во-первых, если человеку предлагается ввести номер телефона, а поле ввода выглядит примерно так:
      +_ (___) ___-__-__
      это вводит его в небольшой ступор — причины объяснил выше:
      1. У старшего поколение сам такой внешний вид поля может вызвать недопонимание
      2. У пользователей из Украины и Беларуси код страны это 3 цифры а не одна. Если человек хочет указать бесплатный номер (8-800) указывать его в формате +7 800 не совсем верно.
      3. У пользователей из региональных городов в коде города может быть 4-5 цифр, а сам номер телефона — соответственно 6-5 цифр
      4. Если сайт ориентирован на корпоративных пользователей (которым как раз удобнее указывать городские номера) — им также удобно в поле «номер телефона» указывать сразу в скобках добавочный. Либо для добавочного делать отдельное поле.
      • 0
        Насчет города и городского телефона написал ниже.
        Насчет масок: мне кажется, пользователю надо позволять вводить символы произвольно, а не по маске. Не нужно пользователей держать за идиотов, неспособных ввести номер телефона.
      • 0
        Код страны/города можно подставлять, например.
  • +1
    Как по мне, так такого плана поля крайне неудобны.
    Почему не сделать 1 поле и уже на сервере разбивать значение как душе угодно? На клиенте по желанию, можно по событию (теряет фокус, достигает определенного кол-ва символов, таймаут) привести к нужному формату (добавить + к номеру телефона, разбить на группы и т.д.).
  • 0
    Некоторые люди, когда у них спрашивают номер телефона — вводят свой городской номер и не парятся.
    А ты гадай, из какого он города (или вообще — страны, если сайт ориентирован на СНГ)
    21-й век на дворе, по IP определите его город
    И потом, если даже он ввел только номер городского телефона, у вас не возникает подозрения, что в 7 введенных символах не уместить код города и телефон?
    • 0
      Промахнулся, это ответ на этот комментарий
    • +1
      по IP определите его город

      у нас например офис находится в Казани, но при этом все городские телефоны московские.

      не возникает подозрения, что в 7 введенных символах не уместить код города и телефон
      возникает, потому что в номере телефона должно быть 10 цифр + код страны.

      Понятно, что можно сделать, например, всплывающую подсказку «не забудьте указать код города» если человек ввел меньше 10 цифр.

      Но, все-таки лично я считаю, что гораздо лучше пользователю сразу дать понять, что от него хотят, чем потом ему напоминать и заставлять возвращаться к полю, которое он уже заполнил.

      И для этого поля «код города» — «номер телефона», как мне кажется, прекрасно выполняют свою функцию.
      • 0
        И для этого поля «код города» — «номер телефона», как мне кажется, прекрасно выполняют свою функцию.

        А мобильный номер как вводить? Там «кода города», формально нет.

        А чем вам не нравиться вариант с примером норма в самой форме (ну или рядом). Когда видишь в каком формате от тебя ждут номер — очень сложно ошибиться.
        • 0
          норма в виде
          "+_ (___) ___-__-__"?

          Я уже два раза ответил на этот вопрос — тем, что количество цифр в коде страны, города и номере телефона разное в разных городах и странах

          Там «кода города»

          Как показывает практика, пользователи в таком случае либо первые три цифры номера мобильного указывают как «код города» либо заполняют только поля «код страны» — "+7" и оставшуюся часть (912-345-67-89) вводят как «номер телефона», пропуская «код города».

          Заметьте, я нигде не уточнял, что «код города» — это обязательное поле. Оно нужно для напоминания (мол не забудьте указать код города), но если его не заполнить, при этом заполнив поле «номер телефона» — валидатор не должен выдавать ошибки.

          Обязательное поле «номер телефона». «Код города» и «код страны» — поля-напоминалки.
          • +1
            Я одного не понимаю — зачем просить пользователя разделить код страны, код города и собственно сам номер.

            Все равно использовать(т.е. звонить, руками или автоматизировано) нужно только «полный» номер.

            «Код города» и «код страны» — поля-напоминалки.

            Так и не увидел, чем вам не нравиться когда в форме присутвуют напоминалки-напоминалки — т.е. или пример в самом поле, либо пример рядом с полем. Оно же проще и компактнее.
  • 0
    На андроиде вставляется только в первый инпут. Или андроид не поддерживается?
  • 0
    Opera 12.00 — копипаста номера не работает. вставляется только в первый инпут
    • 0
      В какой-то момент забыл об опере, и не протестировал. Исправил.
  • 0
    Автору спасибо, было бы не плохо ещё реализовать такую фичу:
    при заполненных полях и вставке текста из буфера, скажем со второго символа (или первого), последующие символы заменялись новыми данными
  • +1
    В любом инпуте, кропе последнего, нажатие на End или Ctrl+→ перебрасывает каретку на следующий.
    • +1
      Тоже самое при нажатии кнопки Home: хочу попасть в начало инпута, а перескакивает на следующий.
  • 0
    Ох, здорово.
    У меня руки не дошли вставку из буфера сделать, но такую же задачку решал.
    Добавил еще работу Home/End.
    Демка | GiHub
    • 0
      Теперь не работает выделение по Shift+[Home|End]. :)
    • 0
      Параллельно делали :)
  • +2
    Когда уже появится
    <input type="creditcard">
    
  • 0
    Ник автора показался знакомым, так и оказалось, раньше соотрудничали на фрилансе.
    В другой статье из одного административного района человек.
    Как узок мир.

    А насчет планина, что сказать, не идеален, но весьма добротно реализован.
  • 0
    А нельзя просто отслеживать все события по нажатию кнопок и производить действия с контролами через js (обрубая дефолтную функциональность)?
    Предложенное Вами решение мне видится штабелем заплаток, которое не факт, что не стрельнет где-то в каком-то браузере.
    • 0
      А ваше чем не заплатка.
      В любом случае костыль получается. Всех вариантов не предусмотреть.
    • 0
      Сейчас так и поступают в редакторах кода. И я думал что бы сделать так. Но передумал по двум причинам:
      1) Скорость мигания курсора не возможно взять из настроек ОС. Его все эмулируют.
      2) Придется верстать инпуты, они не могут быть системными.
  • 0
    Отлично, спасибо!
    И сразу бага: когда курсор находится в конце одного из заполненных инпутов, если при этом нажать Shift, курсор перемещается в следующий инпут. Нелогично это потому, что я нажимаю шифт, чтобы перескочить в предыдущий инпут при помощи Shift+Tab.
    • 0
      Да, исправил. Спасибо.
  • 0
    спасибо
  • 0
    Казалось бы такая тривиальная задача, но далеко не всем хватает времени/желания ее реализовать в своих проектах. Спасибо большое.
  • +10
    Понасуют кривых скриптов на сайты, а потом сиди и мучайся: то вставка не работает, то выделение, то хрен знает как это заполнять с мобильника.
  • 0
    Вместо использования атрибута class для логики, лучше используйте data-* атрибуты. Оставьте class для представления.
    • 0
      Принято завязываться на классы. Так быстрее.
      • –1
        Ну, в истории веб дева много чего «принято». Таблицами верстать, 1х1-пиксельными гифами забивать… Плевать на кросс-браузерность и стандарты с высокой колокольни… Но это не значит, что так нужно делать всегда.

        То, что оно на синтетическом тесте в два раза медленнее я не спорю, но дело не в этом. Я более чем уверен, что data-* селекторы в будущем соптимизируют. А вот себя соптимизировать и писать по стандарту можно уже сейчас…
  • 0
    в демо при заполнении последнего поля номеря курсор не переходит на дату, поэтому демонстрацию считаю не полной ))
    • 0
      Можешь насладиться демонстрацией во время бронирования отеля :)
  • 0
    В iPade демо не срабатывает
    • 0
      Does not work in iOS

      К сожалению. В iOS нельзя сделать переместить фокус из одного ипута в другой.
  • 0
    Чего-то с кодировкой:

    asyncTest("paste symbols : [|◊] to [|◊]", function() {
    • 0
      Под маком отображаются) Заменил небезопасные символы. Спасибо.
  • 0
    Есть большой минус: если я заполнил первый инпут и нажал таб (стандартное поведение), то фокус автоматически переходит на 3-й инпут.
    Советую почитать, как с этим боролся Сергей Чикуёнок: chikuyonok.ru/2010/07/simple-things/
  • 0
    Один инпут всегда лучше нескольких. Лучше — когда данные, введённые в один инпут автоматически проверяются при вводе и при необходимости — разбиваются на группы, видимые пользователю.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.