[FetchIt] - Форма с валидацией номера телефона и выбором страны
Привет форум!
Решил раскрыть такой кейс, как форма с полем ввода номера телефона, ведь с такой задачей разработчик сталкивается частенько. Она далеко непростая и имеет подводные камни. Так давайте же нырнём и первое, что нужно сделать — это разбить её на подзадачи.
— Устанавливаем FetchIt. Напоминаю, вчера я выпустил полноценную замену AjaxForm под названием FetchIt. Он также бесплатен и доступен на маркетплейсах modx.com и modstore.pro.
— Вызываем сниппет FetchIt в том месте вёрстки где находится наша форма.
— Для простоты примера, представим, что у нас вёрстка на Bootstrap и чанк bootstrap.form.example будет выглядеть так:
Уже на данном этапе у нас форма будет работать, отправлять письма, записывать формы в БД и валидировать поля, но т.к. у нас задача сложнее, то продолжим.
— Подключим библиотеку intl-tel-input, именно она нам поможет реализовать выбор страны, валидацию и форматирование. Для простоты примера сделаем это через CDN. Сначала стили.
А скрипт в виде ES модуля:
Далее нам нужно инициализировать библиотеку для каждого поля ввода телефона, указав некоторые свойства. Со всеми её возможностями вы можете ознакомиться в репозитории библиотеки.
Теперь наша форма выглядит таким образом:
— Осталось немного. А точнее подружить intl-tel-input и FetchIt. Для этого нам нужно добавить обработчик на событие fetchit:before, где и будет производиться валидация.
Готово! Теперь при попытке ввести невалидный номер телефона, пользователь увидит сообщение об ошибке.
А в случае ввода валидного номера в любом формате, вы получите единый.
* Все данные и совпадения случайные.
Тут надо проговорить пару вещей:
— Любая валидация на стороне клиента небезопасна и нужна только для удобства пользователя. Вы можете также улучшить её на стороне сервера с помощью FormIt.
— Для простоты примера здесь используется CDN и естественно для продакшена нужно подключать библиотеку другими способами.
Всем желаю мира и спасибо за внимание.
Документация
Репозиторий на GitHub
☕ Угостить чашкой кофе
Решил раскрыть такой кейс, как форма с полем ввода номера телефона, ведь с такой задачей разработчик сталкивается частенько. Она далеко непростая и имеет подводные камни. Так давайте же нырнём и первое, что нужно сделать — это разбить её на подзадачи.
- Валидация: Тут пока всё понятно, нам по хорошему нужно валидировать номер телефона.
- Форматирование: А с этим пунктом веселее, т.к. пользователи могут писать номер телефона в разных форматах: 8 *** *** ** **, +7 ***-***-**-** +7 (***) *******, 8 (***) *** **-** и еще 100500 вариантов.
- Разные страны: А теперь всё серьезнее, дело в том, что разные страны это разное форматирование и соответственно разная валидация.
Решение
— Устанавливаем FetchIt. Напоминаю, вчера я выпустил полноценную замену AjaxForm под названием FetchIt. Он также бесплатен и доступен на маркетплейсах modx.com и modstore.pro.
— Вызываем сниппет FetchIt в том месте вёрстки где находится наша форма.
[[!FetchIt?
&form=`bootstrap.form.example`
&snippet=`FormIt`
&hooks=`email,FormItSaveForm`
&formName=`Заявка на обратный звонок`
&validate=`name:required,phone:required`
&fieldNames=`name==Имя,phone==Контактный телефон,pageId==ID страницы`
&emailSubject=`Заявка на обратный звонок`
... остальные параметры FormIt
]]
— Для простоты примера, представим, что у нас вёрстка на Bootstrap и чанк bootstrap.form.example будет выглядеть так:
<form>
<div class="mb-3">
<input type="text" name="name" class="form-control rounded-3" placeholder="Ваше имя" value="[[+fi.name]]">
<div data-error="name" class="invalid-feedback">[[+fi.error.name]]</div>
</div>
<div class="mb-3">
<input type="tel" name="phone" class="form-control rounded-3" placeholder="Телефон" value="[[+fi.phone]]">
<div data-error="phone" class="invalid-feedback">[[+fi.error.phone]]</div>
</div>
<button class="btn btn-primary rounded-3 w-100" type="submit">Отправить</button>
</form>
Уже на данном этапе у нас форма будет работать, отправлять письма, записывать формы в БД и валидировать поля, но т.к. у нас задача сложнее, то продолжим.
— Подключим библиотеку intl-tel-input, именно она нам поможет реализовать выбор страны, валидацию и форматирование. Для простоты примера сделаем это через CDN. Сначала стили.
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@17/build/css/intlTelInput.min.css">
<!-- Если у вас Bootstrap, то нужно добавить еще и парочку стилей -->
<style>
.iti { display: block; } // Для того, чтобы поле было на всю доступную ширину
form[data-fetchit] [data-error="phone"] { display: block; } // Библиотека нарушает нужную для Bootstrap разметку, поэтому такой хак
</style>
А скрипт в виде ES модуля:
<script type="module">
import intlTelInput from 'https://cdn.jsdelivr.net/npm/intl-tel-input@17/+esm'
</script>
Далее нам нужно инициализировать библиотеку для каждого поля ввода телефона, указав некоторые свойства. Со всеми её возможностями вы можете ознакомиться в репозитории библиотеки.
<script type="module">
import intlTelInput from 'https://cdn.jsdelivr.net/npm/intl-tel-input@17/+esm'
document.querySelectorAll('form[data-fetchit] [name="phone"]').forEach((input) => {
intlTelInput(input, {
autoPlaceholder: 'aggressive', // Изменять плейсхолдер на формат выбранной страны
initialCountry: 'ru', // Код страны при инициализации
preferredCountries: ['ru', 'kz', 'by', 'ge', 'us'], // Список кодов стран, которые будут в начале списка
utilsScript: 'https://cdn.jsdelivr.net/npm/intl-tel-input@17/build/js/utils.js', // Подключение вспомогательного скрипта, он нужен для валидации и форматирования
});
});
</script>
Данный пример будет работать даже в том случае, если у вас несколько форм с вводом телефона.Теперь наша форма выглядит таким образом:
— Осталось немного. А точнее подружить intl-tel-input и FetchIt. Для этого нам нужно добавить обработчик на событие fetchit:before, где и будет производиться валидация.
<script type="module">
import intlTelInput from 'https://cdn.jsdelivr.net/npm/intl-tel-input@17/+esm'
document.querySelectorAll('form[data-fetchit] [name="phone"]').forEach((input) => {
intlTelInput(input, {
autoPlaceholder: 'aggressive',
initialCountry: 'ru',
preferredCountries: ['ru', 'kz', 'by', 'ge', 'us'],
utilsScript: 'https://cdn.jsdelivr.net/npm/intl-tel-input@17/build/js/utils.js',
});
});
document.addEventListener('fetchit:before', (e) => {
const { form, formData, fetchit } = e.detail; // Получим ссылку на форму, экземпляры FormData и FetchIt
const phoneInput = form.querySelector('[name="phone"]'); // Поищем в форме поле с телефоном
if (!phoneInput) return; // Если не нашли, то прерываем работу обработчика
const iti = window.intlTelInputGlobals.getInstance(phoneInput); // Получаем экземпляр поля intlTelInput
if (iti.isValidNumber()) { // Проверяем поле на валидность и если валидно...
formData.set('phone', iti.getNumber()); // Приводим введенное пользователем значение в нормальный формат
return; // И прерываем работу обработчика
}
// Иначе
fetchit.setError('phone', 'Введите пожалуйста корректный номер телефона'); // Выводим сообщение об ошибке
e.preventDefault(); // Прерываем отправку формы
});
</script>
Готово! Теперь при попытке ввести невалидный номер телефона, пользователь увидит сообщение об ошибке.
А в случае ввода валидного номера в любом формате, вы получите единый.
* Все данные и совпадения случайные.
Заключение
Тут надо проговорить пару вещей:
— Любая валидация на стороне клиента небезопасна и нужна только для удобства пользователя. Вы можете также улучшить её на стороне сервера с помощью FormIt.
— Для простоты примера здесь используется CDN и естественно для продакшена нужно подключать библиотеку другими способами.
Всем желаю мира и спасибо за внимание.
Документация
Репозиторий на GitHub
☕ Угостить чашкой кофе
Комментарии: 13
Спасибо, что поделился ?
Добрый день!
Решил протестировать данный компонент, но столкнулся со следующими проблемами.
1. Пробовал разные версии jquery но постоянно одна и та-же ошибка при отправки Скрин
2. Дополнительно подключили Notyf и на имени всплывающее уведомление работает, а на телефоне, если подключить все скрипты не работает. (видимо надо править код валидатора в этом примере)
3. В данном решении конечно не хватает маски для телефона.
На сколько я понимаю для данного компонента не нужен jquery, но все же с ним у него конфликт.
В вообще было бы здорово, если бы компонент прятал саму форму из html так-как роботы зачастую уже надоели и все защиты обходят. (Наверное это больше вопрос к fiormit)
Сама отправка формы, работает.
Еще раз спасибо за ваш труд!
Решил протестировать данный компонент, но столкнулся со следующими проблемами.
1. Пробовал разные версии jquery но постоянно одна и та-же ошибка при отправки Скрин
2. Дополнительно подключили Notyf и на имени всплывающее уведомление работает, а на телефоне, если подключить все скрипты не работает. (видимо надо править код валидатора в этом примере)
3. В данном решении конечно не хватает маски для телефона.
На сколько я понимаю для данного компонента не нужен jquery, но все же с ним у него конфликт.
В вообще было бы здорово, если бы компонент прятал саму форму из html так-как роботы зачастую уже надоели и все защиты обходят. (Наверное это больше вопрос к fiormit)
Сама отправка формы, работает.
Еще раз спасибо за ваш труд!
День добрый!
1. У компонента нет и не может быть никаких конфликтов с jquery. Даже по stacktrace в вашем скрине видно, что ошибка не связана с fetchit. В вашем конкретном случае надо разбираться, уверен, выясниться что ошибка где-то в вашем коде.
2. Поведение ожидаемое, в данной заметке показан пример дополнительной валидации на стороне клиента, это значит, что и за поведение также разработчик отвечает. В вашем случае, если вы хотите показывать всплывающее уведомление, то нужно добавить:
3. Не соглашусь, библиотека intl-tel-input как раз даёт возможность вводить номера телефонов в любом формате, а маска прямо противоречит этому. Вы можете использовать любое готовое решение или своё, а FetchIt без разницы что вы там сделаете, он просто собирает все данные с полей ввода формы и вскармливает их указанному сниппету.
1. У компонента нет и не может быть никаких конфликтов с jquery. Даже по stacktrace в вашем скрине видно, что ошибка не связана с fetchit. В вашем конкретном случае надо разбираться, уверен, выясниться что ошибка где-то в вашем коде.
2. Поведение ожидаемое, в данной заметке показан пример дополнительной валидации на стороне клиента, это значит, что и за поведение также разработчик отвечает. В вашем случае, если вы хотите показывать всплывающее уведомление, то нужно добавить:
fetchit.setError('phone', 'Введите пожалуйста корректный номер телефона');
FetchIt.Message.error('Введите пожалуйста корректный номер телефона'); // <-- ЭТУ СТРОКУ
e.preventDefault();
3. Не соглашусь, библиотека intl-tel-input как раз даёт возможность вводить номера телефонов в любом формате, а маска прямо противоречит этому. Вы можете использовать любое готовое решение или своё, а FetchIt без разницы что вы там сделаете, он просто собирает все данные с полей ввода формы и вскармливает их указанному сниппету.
На сколько я понимаю для данного компонента не нужен jquery, но все же с ним у него конфликт.У FetchIt нет и не может быть конфликтов с jquery.
В вообще было бы здорово, если бы компонент прятал саму форму из html так-как роботы зачастую уже надоели и все защиты обходят. (Наверное это больше вопрос к fiormit)Я подумаю как-нибудь о защите от спама, может что-то интересное и надумаю.
Еще раз спасибо за ваш труд!Пожалуйста!
На данный момент есть баг связанный с вызовом сниппета на fenom, завтра выпущу патч с исправлением.
Добрый день!
Проблему я все-же нашел, она связанна с дополнением AdminPanel (если смотреть сайт в инкогнито, то таких проблем нет)
Проблему я все-же нашел, она связанна с дополнением AdminPanel (если смотреть сайт в инкогнито, то таких проблем нет)
Не удалось загрузить и создать пакет с подписью: fetchit-
Официальный маркетплейс болеет, т.к. там ведутся работы. Не только FetchIt недоступен, но и некоторые другие. Используйте modstore.pro
Здравствуйте, пробую заменить AjaxForm на FetchIt, почему-то не срабатывает хук FormItSaveForm. Письма в админке не сохраняются. Вывожу так:
[[!FetchIt?
&snippet=`FormIt`
&form=`contactFormTpl`
&hooks=`spam,FormItSaveForm,email`
&formName=`Рассчитать стоимость здания`
&emailSubject=`Тема письма`
&emailTo=`[[++emailsender]]`
&emailFrom=`no-reply@rmse.ru`
&validate=`nospam:blank,name:minLength=^2^,phone:phone:required`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено`
&phone.vTextRequired=`На какой номер телефона Вам перезвонить?`
&name.vTextRequired=`Укажите Ваше имя`
&fieldNames=`name==Имя,phone==Телефон,pageurl==Страница отправки,message==Сообщение,pageId==ID Страницы`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено`
]]
Убедитесь, что хук spam отрабатывает правильно
Спасибо, дело было в нем! Подскажите пожалуйста варианты избавления от спама.
Компонент recaptchav3 совместим с FetchIt, можете использовать его
Подскажите пожалуйста, почему не работает перевод в письме с латиницы, вроде как за это отвечает &fieldNames=`name==Имя,phone==Контактный телефон,pageId==ID страницы`
Но мне по прежнему приходят письма без переводов.
И как добавить свои данные например отправлять название страницы или url адрес.
Можно ли как то использовать одну форму но передавать в ней разные тем? Например есть на страницы 3 услуги, что бы не платить форму, было бы удобно передавать в теме её название. Заранее спасибо!
Но мне по прежнему приходят письма без переводов.
И как добавить свои данные например отправлять название страницы или url адрес.
Можно ли как то использовать одну форму но передавать в ней разные тем? Например есть на страницы 3 услуги, что бы не платить форму, было бы удобно передавать в теме её название. Заранее спасибо!
Подскажите пожалуйста, почему не работает перевод в письме с латиницы, вроде как за это отвечает &fieldNames=`name==Имя,phone==Контактный телефон,pageId==ID страницы`Параметр fieldNames отвечает за вывод названий полей в админке на странице просмотра сохраненных форм, при использовании хука FormitSaveForm
Но мне по прежнему приходят письма без переводов.
За формирование письма отвечаете вы. Создайте и укажите нужный вам чанк письма в параметре emailTpl и реализуйте логику переводов там. Кстати, это не я так решил, а разработчик FormIt и если вдруг покажется, что это не логично, то вопросы к ним.
И как добавить свои данные например отправлять название страницы или url адрес.Либо используйте хуки FormIt, либо скрытые поля в форме. Первый вариант лучше.
Можно ли как то использовать одну форму но передавать в ней разные тем? Например есть на страницы 3 услуги, что бы не платить форму, было бы удобно передавать в теме её название. Заранее спасибо!Можно, при вызове сниппета укажите разные значения параметра emailSubject или если у вас одна форма, то используйте связку js, скрытого поля subject и параметра emailUseFieldForSubject
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.