Валидация формы обратной связи.

Вступление.

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

Прежде чем приступать работе, нужно ясно понять:
— что из себя будет представлять форма обратной связи;
— какие поля будет в себя включать;
— какие данные мы будем проверять и по какому критерию;
— какой лучше использовать метод и способ отправки данных формы на сервер.

Немного подумав, мы решили, что форма будет иметь следующие поля:

  1. имя — ведь нам нужно как-то обращаться к пользователю, когда мы будем писать ему ответ;
  2. электронная почта — мы же должны знать, куда отправлять ответ;
  3. тема сообщения — тоже необходимая информация, по ней мы определимся, кто будет отвечать на это письмо;
  4. текст сообщения — здесь комментарии излишни.

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

Мы не будем подробно рассматривать этапы создания HTML вёрстки и оформления её стилями, т.к. наша главная задача — написать скрипт валидации введённых данных и отправить их на сервер. Поэтому сразу представим готовую разметку HTML и таблицу стилей для него с минимумом комментариев.

HTML-разметка формы обратной связи.

Отметим лишь один элемент данной формы:

В этот <span> мы будем выводить красиво оформленное сообщение об ошибке.

Таблица стилей для формы обратной связи.

Представлены только стили, относящиеся непосредственно к самой форме обратной связи.

Очень важно.
Для уменьшения размера таблицы стилей, я не буду приводить свойства с вендорными префиксами, обеспечивающими кроссбраузерность. Не забывайте прописывать их при реализации своих проектов.

Критерии валидации формы обратной связи.

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

Во-первых, для всех полей формы проверяем заполнены они или нет. Это самая простая проверка.

Это очень важно.
Для следующих проверок будут использоваться регулярные выражения. Мы не будем разбирать, как составляются и работают регулярные выражения. Это отдельная и достаточно объёмная тема для разговора. О регулярных выражениях вы сможете прочитать здесь.
При написании скрипта валидации мы будем использовать уже готовые паттерны (шаблоны) RegExp.

Во-вторых, поле «Ваше имя». Давайте определимся, что мы ожидаем получить реальное имя человека на русском языке. Значит поступившие данные должны содержать только прописные и строчные буквы русского алфавита. Разрешим ещё и пробел — пользователь кроме имени может указать ещё и своё отчество. Наличие любых других символов приведёт к ошибке.
Паттерн RegExp для такой проверки будет выглядеть так: /^[а-яёА-ЯЁ\s]+$/.

В-третьих, поле «Электронная почта». Здесь особых объяснений не нужно.
Паттерн RegExp для этого поля выглядит так:
/^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z])+$/.

В-четвёртых, поля «Тема сообщения» и «Текст сообщения». В этих полях допустимы любые символы. Более серьёзная проверка на спам и защита от хакеров осуществляется в php-скрипте, в который мы передадим данные формы, но это находится за пределами темы нашей статьи.

Начинаем писать Javascript валидации формы.

Для ограничения области видимости нашего скрипта и исключения конфликтов с другими js-скриптами, разместим код в анонимной самозапускающейся функции.

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

Создание экземпляров формы обратной связи.

В-первую очередь, создадим коллекцию всех форм, которые расположены на странице. Далее, с помощью метода for...of переберём полученную коллекцию, при этом создадим экземпляр текущей формы, используя конструктор класса Form.

Весь дальнейший JS-код мы будем писать внутри конструкции class Form { ... }.

Прежде всего рассмотрим конструктор класса Form. Конструктор инициализирует ряд объектов и переменных, содержащих информацию об экземпляре галереи. В качестве аргумента конструктор принимает объект формы обратной связи, экземпляр которого создаётся в данный момент.

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

Конструктор, кроме инициализации объектов и переменных, вызывает функцию registerEventsHandler, в которой регистрируются все обработчики событий.

На данный момент мы зарегистрируем только один обработчик, который фиксирует событие click на кнопке отправки данных формы обратной связи. При наступлении события вызывается функция validForm, запускающая валидацию формы.

Запуск валидации формы обратной связи.

Прежде чем переходить к валидации данных, нужно эти данные получить. Для этой цели будем использовать объект FormData, который автоматически считает поля формы и их значения. Объект содержит ряд методов, которые мы будем использовать в дальнейшем:

formData.keys()
Возвращает iterator, который позволяет пройтись по всем ключам, содержащимся внутри обьекта formData.
formData.get()
Возвращает первое значение ассоциированное с переданным ключом из объекта formData.
formData.append()
Создаёт новое поле объекта formData и присваивает ему значение.

Итак, объект со значениями полей формы обратной связи в формате 'property': 'value' получены. И что же нам с ними делать дальше?
Чтобы перебрать свойства объекта, воспользуемся циклом for...of. Этот цикл последовательно переберёт свойства property и вызовет функцию getError, которая будет сравнивать значение свойства с паттерном RegExp и возвращать результат сравнения в виде пустой строки или текста ошибки валидации.

Посмотрим, как теперь выглядит функция validForm:

Валидация введёных значений формы обратной связи.

Теперь мы знаем как получить имя свойства объекта, которое равно имени поля формы, знаем как получить значение этого свойства. Теперь нужно решить, каким способом мы будем назначать полученному свойству соответствующий ему паттерн RegExp для проверки корректности его значения.
Обычно это делается с помощью конструкций if ... else или switch.
Но есть ещё один способ, который заменяет эти конструкции — использование объектного литерала. Мы сэкономим несколько строчек кода, при сохранении функциональности. Давайте и остановимся на этом способе.

Валидация шаг за шагом

Давайте, шаг за шагом, рассмотрим, как работает функция getError на примере валидации поля ‘usermail’.

  • 1

    Сначала мы создаём литеральный объект validate, у которого значением свойства является анонимная функция.

  • 2

    Затем мы вызываем анонимную функцию, указывая свойство, значением которого эта функция является.

  • 3

    В теле функции мы осуществляем проверку с использованием объекта formData, в котором находятся значения всех полей формы обратной связи. В нашем случае это formData.get('usermail').
    Сначала мы сравниваем длину formData.get('usermail') с 0.

    Затем сравниваем formData.get('usermail') с шаблоном RegExp patternMail

  • 4

    Если условие сравнения окажется истинным, то присваиваем переменной error соответствующее значение из массива ошибок: errorMess[2] или errorMess[3]
    Если оба условия сравнения ложны, то переменной error ничего не присваивается.

  • 5

    Возвращаем значение переменной error, которое является или строкой с текстом ошибки или пустой строкой.

Обработка переменной error.

Опять возвращаемся к функции validForm. После вызова функции getError мы получили значение переменной error. А что с ней будем делать дальше? А это зависит от того, что в себе содержит эта переменная: строку с текстом ошибки или пустую строку.
Начнём с того, что сравним длину строки, содержащейся в переменной error с 0. Если результат проверки не будет равен 0, значит в error находится текст ошибки и нужно показать эту ошибку пользователю. Для этого мы создадим функцию showError, у которой есть два аргумента:
1. property — имя поля, в которое ввели некорректные данные;
2. error — строка с текстом ошибки.
Кроме этого, нужно установить флаг ошибки, присвоив переменной iserror значение true.

Если валидация ошибок не обнаружила, то вызываем функцию sendFormData, которая отправляет данные на сервер. Аргументом этой функции является объект formData. Напоминаем, что в нём хранятся данные формы, записанные в формате 'property': 'value'.

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

Теперь настало время разобраться, как вывести ошибки валидации на экран.
Как уже говорилось, для этой цели будем использовать функцию showError с аргументами property и error.

Вывод ошибок валидации на экран.

При создании разметки HTML мы отметили, что ошибку будем выводить в элемент <span> с классом .error. У вас может возникнуть естественный вопрос: в вёрстке четыре таких элемента, как мы определим, в какой из них записывать ошибку? Ведь у них нет ни id, ни атрибутов data-..., с помощью которых можно было бы идентифицировать нужный нам <span>.
Всё очень просто, мы это сделаем с помощью DOM-навигации, но для начала давайте вспомним HTML-разметку для одного поля формы.

Рассмотрим ещё раз шаг за шагом DOM-навигацию по элементам, так, как она реализована в функции showError:

  • 1

    Используя аргумент property, который является значением атрибута name элемента <input>, находим этот <input>. Это будет отправная точка DOM-навигации.

  • 2

    Мы видим, что <span class="error">, расположен сразу же после элемента <div>, который является родительским по отношению к <input>. Находим этот <div> с помощью метода DOM-навигации parentElement.

  • 3

    Теперь несложно добраться и до самого <span>, используя метод nextElementSibling и записать в него текст ошибки.

  • 4

    Изменяем стиль отображения <input>, добавив ему новый класс .form-control_error.

Полный код функции showError выглядит так:

Как видно из приведённого JS-кода, для поиска элемента <span> мы использовали статическую функцию getElement. Код функции очень простой и реализует шаги 2 и 3 приведённого выше алгоритма DOM-навигации. Параметром функции является элемент, в который введены ошибочные данные.
Запишем код функции сразу после конструктора класса Form:

Проверяем функционирование скрипта валидации формы, внося разные ошибки при заполнении формы. Скрипт прекрасно их отлавливает и выводит сообщения. Кажется, что работу на скриптом валидации мы закончили. Но не будем торопиться.
Вы обратили внимание, что когда пробуете отредактировать текст, относящаяся к нему ошибка не пропадает, создавая определённые неудобства? Давайте решим эту проблему путём удаления содержимого <span class="error">.

Удаление текста ошибки при получении фокуса элементом.

Событие focus вызывается, когда вы нажимаете мышкой на элементе формы. Для того, чтобы отследить появление этого события, давайте опять используем метод addEventListener, применив его к объекту form. Добавим в функцию registerEventsHandler следующий код:

Ну и теперь посмотрим код функции cleanError. Ничего сложно в ней нет, она очень похожа на функцию showError, поэтому отдельно расписывать её не будем.

Прекрасно, теперь ошибка пропадает, если мы устанавливаем курсор в поле ввода. Кажется теперь можно перейти к отправке данных формы на сервер. Давайте пока не будем торопиться.
Будет очень здорово, если мы запустим валидацию введённых данных при потере фокуса элементом, т.е. когда пользователь кликнет на другом месте экрана и курсор уйдёт с текущего поля ввода. Это событие называется blur.

Валидация данных при потере фокуса поля ввода.

Первое, что нам нужно сделать, это повесить обработчики события blur на все поля ввода формы обратной связи. У нас уже есть коллекция этих элементов, которую мы получили при инициализации скрипта — fields. Оптимальным решением будет использование метода for ... of. Этот метод совершает обход коллекции элементов полей ввода и назначает обработчик события blur вызовом метода addEventListener для каждого элемента.
Добавим в конец функции registerEventsHandler следующий код:

Как видно из кода, при потере фокуса активным элементом, вызывается функция validBlurField. Код функции простой, но есть одна особенность. Перед вызовом функции getError создаётся пустой объект formData. В этот объект заносятся значения property и value, являющиеся свойствами объекта e.target.

Код функции validBlurField и комментарии к нему:

Валидация необязательных к заполнению полей формы обратной связи.

Теперь разберём поведение созданного нами скрипта при наличии в форме поля необязательного к заполнению. Давайте создадим такое поле, пусть это будет ввод города.

Реально таких полей может быть несколько и наша задача исключить ошибки при валидации данных из этих полей ввода. Для этой цели будем проверять наличие свойства, имеющего имя проверяемого поля, в объекте validate. Если такое свойство существует, то данное поле ввода обязательно к проверке.

Обновлённый код функции getError:

Вот теперь все возможные варианты валидации формы обратной связи рассмотрены, пользователь всё же ввёл корректные данные и теперь они должны быть отправлены на сервер для дальнейшей обработки и отправки в виде письма на наш email.

Асинхронная отправка данных формы обратной связи на сервер.

Для отправки данных на сервер будем использовать функцию sendFormData. Непосредственно отправку данных будем осуществлять с помощью объекта XMLHttpRequest. Он позволяет делать HTTP-запросы к серверу без перезагрузки страницы, т. е. асинхронно. Аргументом функции является объект formData, в котором содержаться имена полей формы и соответствующие им значения.

Код функции sendFormData и комментарии к нему:

Итак, мы создали форму обратной связи, ввели в неё данные, сделали валидацию этих данных и отправку их на сервер.

Расширяем форму обратной связи.

Данный скрипт не ограничивает форму обратной связи четырьмя полями, их может быть значительно больше. Структура HTML-верстки и JS-скрипта позволяют гибко, без особых усилий расширить данную форму. Например, вы решили добавить поле, в которое пользователь будет вводить номер своего мобильного телефона. Для этого нужно сделать всего три шага:

  • 1

    Добавить поле ввода, для этого можно скопипастить поле ввода имени пользователя. Прописать ему название — «Номер Вашего телефона» и атрибуту name прописать значение ‘userphone’.

  • 2

    В массив с ошибками errorMess добавить текст ошибки, которая может возникнуть при валидации номера телефона.

  • 3

    Создать шаблон RegExp для валидации введённого номера. Добавить объектному литералу validate в функции getError, свойство ‘userphone’ и, относящуюся к этому свойству, анонимную функцию, в которой будете использовать созданный шаблон.

По такому же принципу вы можете добавлять и другие поля в свою форму обратной связи. Единственная трудность, которая может вам встретиться — это создание паттерна RegExp, остальное делается простым копипастом соседних полей формы.

Комментарии

Всего: 11 комментариев
Требования при посте комментариев:
  1. Комментарии должны содержать вопросы и дополнения по статье, ответы на вопросы других пользователей.
    Комментарии содержащие обсуждение политики, будут безжалостно удаляться.
  2. Для удобства чтения Вашего кода, не забываейте его форматировать. Вы его можете подсветить код с помощью тега <pre>:
    <pre class="lang:xhtml"> - HTML;
    <pre class="lang:css"> - CSS;
    <pre class="lang:javascript"> - JavaScript.
  3. Если что-то не понятно в статье, постарайтесь указать более конкретно, что именно не понятно.
  • Доброго времени суток!
    Подскажите пожалуйста, как в Ваш скрипт добавить, пользовательские классы, что
    1. поле находится в состоянии — undefined (не определено), ожидает ввода данных, курсор в поле мигает:
    .undefined {border-color: #ffa806;} — бордер жёлтый
    и общее для всех полей,
    2. прошли проверку по RegExp
    .valid {border-color: #44b164;} — бордер зёлёный
    3. не прошли проверку по RegExp
    .invalid {border-color: #d90000;} — бордер красный
    Заранее признателен за ответ!

    • 1. курсор находится в поле, значит это поле в фокусе. Найдите в таблице стилей класс ‘.form-control:focus’ и пропишите для него нужные вам значения.

      2. В функции validForm(), есть условие, которое проверяет наличие ошибки в поле. Если условие выполняется, то вызывается функция showError, отображающая ошибку.
      if (error.length != 0) {
      iserror = true;
      showError(property, error);
      }
      добавьте к ней else
      } else {
      showSuccess(property);
      }
      Теперь нужно создать функцию showSuccess, которая будет работать аналогично функции showError.

      function showSuccess(property) {
      var formElement = form.querySelector(‘[name=’ + property + ‘]’);
      formElement.classList.add(‘form-control_success’);
      }
      Добавьте в таблицу стилей класс form-control_success и пропишите нужные стили в нём.
      По-большому счёту, можно и даже нужно, функции showError и showSuccess свести в одну, упростив js-код, т.к. они по функционалу одинаковые, просто присваивают разные классы.

      3. За красный цвет border при ошибке отвечает класс form-control_error — это реализовано.

      • Вальдемар, большое спасибо за развёрнутый и оперативный комментарий! Буду пилить ). Форма мне очень понравилась.

  • Здравствуйте, а как идет сама передача данных? Я внедрил, настроил под свой стиль данную форму. Но до этого отправка проходила спокойно через php файл. Теперь я нажимаю на submit и ничего не происходит вообще.. Как можно решить проблему?
    В js прописываю путь к данному файлу php.. Та же проблема.. Убирался уже в форме action и оставлял только путь в js. Тоже толку 0.

  • Выдает такую ошибку:
    Uncaught TypeError: validate[property] is not a function
    at getError (validation.function.js:78)
    at HTMLInputElement.validForm (validation.function.js:35)
    getError @ validation.function.js:78
    validForm @ validation.function.js:35

  • Здравствуйте) Решил добавить в форму чекбокс: сделал разметку в html, указал type=»checkbox» и name=»checkbox», а вот как добавить в js код, не могу разобраться. Понимаю, что должен быть код вроде этого (по аналогии с другими полями формы)

    checkbox: () => {
    if (formData.getAttribute(«type») === «checkbox» && checkbox.checked === false) {
    error = Form.errorMess[3];
    }
    }
    но, что-то пошло не так))) Не подскажете, как правильно его интегрировать? Спасибо!)

  • Здравствуйте! Подскажите пожалуйста, как добавить в эту форму проверку чекбокса? Хочется сделать по аналогии с показом ошибок, как в других полях формы. Рассуждаю таким образом — есть инпут с type=»checkbox», его проверяем на состояние checked и если это состояние = false, то выводим ошибку. Если галочка отмечена, то ничего не выводим и форма проходит валидацию. Возникли трудности с внедрением в форму. Спасибо!

    • Вальдемар Александр Ответить 4 января 2023 в 20:16

      Проблема в том, что formData() не собирает неотмеченные чекбоксы, поэтому для их валидации нужен другой подход.
      В ф-ии getError() с помощью ‘querySelectorAll’ создайте коллекцию чекбоксов, а потом переберите её, проверяя у каждого элемента наличие атрибута ‘checked’. Если атрибут отсутствует, выведите под ним текст соответствующей ошибки.

      • Александр Вальдемар Ответить 5 января 2023 в 13:53

        Большое спасибо за ответ! Теперь мне ясно, почему не получалось). Еще раз спасибо!)

      • Василий Вальдемар Ответить 29 января 2023 в 00:44

        Помогите пожалуйста, я в отчаянии. Не получается обработать ошибку ненажатого чекбокса( Может быть можно как-то с вами связаться? Спасибо.

Добавить комментарий для Вальдемар

Ваш адрес email не будет опубликован. Обязательные поля помечены *