[AjaxFormitLogin] AjaxForm на стрероидах и чистом JS
Приветствую, коллеги. Всех с наступающим! В честь этого праздника, я решил сделать сообществу подарок и собрал некоторые свои наработки в пакет. Надеюсь в новом году он кому-нибудь облегчит жизнь. Примеры вызовов можно найти в папке компонента в подпапке templates.
Отличия от AjaxForm:
1. Нет jQuery.
2. Для показа уведомлений используется библиотека IziToast.
3. Принимает параметр clearFieldsOnSuccess, тем самым позволяя управлять очисткой полей при успешной оправке формы.
4. Принимает параметр transmittedParams (значение должно быть валидным JSON), который позволяете передавать в JS кастомные параметры отдельно при успешной, отдельно при неудачной отправке.
5. Позволяет отображать процесс загрузки файлов на сервер, для этого нужно указать параметр showUploadProgress со значением 1.
6. Событие af_complete заменено на afl_complete.
8. Работают редиректы. Для этого необходимо указать параметр redirectTo (абсолютная ссылка или ID ресурса) и, при необходимости изменить стандартное значение в 2с, redirectTimeout (в милисекундах) для задания задержки перед переходом на другую страницу.
9. Добавлен метод помогающий валидировать чекбоксы. Для его работы необходимо проверяемому чекбоксу добавить атрибут data-afl-required, где значением будет ключ указанный в параметре validate, а также нужно добавить скрытое поле с этим именем в форму. Самому чекбоксу имя можно не указывать.
10. Нет поддержки капчи от гугла, но встроена собственная защита от спама по методу Алексея Смирнова. Для активации нужно в вызове указать параметр spamProtection со значением 1.
11. Есть возможность регистрации, авторизации, сброса пароля и редактирования личных данных, при условии установки компонента FormIt.Подробнее о поддерживаемых параметрах можно прочитать в этой заметке
12. При обновлении данных пользователя добавлено системное событие aiOnUserUpdate, которое получает следующие данные $user — объект обновленного пользователя, $profile — его профиль, $data — переданные данные.
Благодарности:
1. @Василий Наумкин за AjaxForm, modExtra и вообще всю базу, которая легла в основу этого компонента.
2. @Баха Волков за код-ревью и подсказки по JS.
3. @Дима Сайт old см. профиль за подсказку по неймингу.
4. @Алексей Смирнов за метод защиты от спама.
Скачать пакет пока можно только с GitHub, как появится в modstore выложу ссылку сюда.
Отличия от AjaxForm:
1. Нет jQuery.
2. Для показа уведомлений используется библиотека IziToast.
3. Принимает параметр clearFieldsOnSuccess, тем самым позволяя управлять очисткой полей при успешной оправке формы.
4. Принимает параметр transmittedParams (значение должно быть валидным JSON), который позволяете передавать в JS кастомные параметры отдельно при успешной, отдельно при неудачной отправке.
5. Позволяет отображать процесс загрузки файлов на сервер, для этого нужно указать параметр showUploadProgress со значением 1.
6. Событие af_complete заменено на afl_complete.
document.addEventListener('afl_complete', e => {
console.log(e.detail.response); // ответ сервера
console.log(e.detail.form); // текущая форма
});
7. Изменен формат ответа сервера.8. Работают редиректы. Для этого необходимо указать параметр redirectTo (абсолютная ссылка или ID ресурса) и, при необходимости изменить стандартное значение в 2с, redirectTimeout (в милисекундах) для задания задержки перед переходом на другую страницу.
9. Добавлен метод помогающий валидировать чекбоксы. Для его работы необходимо проверяемому чекбоксу добавить атрибут data-afl-required, где значением будет ключ указанный в параметре validate, а также нужно добавить скрытое поле с этим именем в форму. Самому чекбоксу имя можно не указывать.
10. Нет поддержки капчи от гугла, но встроена собственная защита от спама по методу Алексея Смирнова. Для активации нужно в вызове указать параметр spamProtection со значением 1.
11. Есть возможность регистрации, авторизации, сброса пароля и редактирования личных данных, при условии установки компонента FormIt.Подробнее о поддерживаемых параметрах можно прочитать в этой заметке
12. При обновлении данных пользователя добавлено системное событие aiOnUserUpdate, которое получает следующие данные $user — объект обновленного пользователя, $profile — его профиль, $data — переданные данные.
Благодарности:
1. @Василий Наумкин за AjaxForm, modExtra и вообще всю базу, которая легла в основу этого компонента.
2. @Баха Волков за код-ревью и подсказки по JS.
3. @Дима Сайт old см. профиль за подсказку по неймингу.
4. @Алексей Смирнов за метод защиты от спама.
Скачать пакет пока можно только с GitHub, как появится в modstore выложу ссылку сюда.
Поблагодарить автора
Отправить деньги
Комментарии: 61
AjaxForm на стреройдахНаверно, имелось ввиду «на стероидах»?
Исправил, спасибо)))
Запиши видео в upd поста или полный обзор, хоть посмотреть как работает. Похвастайся :)
Артур подскажи пожалуйста, для этого вызова(из примеров взял) получается надо написать плагин который будет сохранять или хук?
Просто при таком вызове, редактирую fullname сохранить нажал, «Данные сохранены», но они не записались
Просто при таком вызове, редактирую fullname сохранить нажал, «Данные сохранены», но они не записались
{'!AjaxFormitLogin' | snippet : [
'form' => 'updateProfileForm',
'snippet' => 'FormIt',
'hooks' => 'AjaxIdentification',
'method' => 'update',
'successMessage' => 'Данные сохранены.',
'clearFieldsOnSuccess' => 0,
'validate' => 'email:required:email',
'validationErrorMessage' => 'Исправьте, пожалуйста, ошибки!',
'email.vTextRequired' => 'Укажите email.'
]}
Дополнительно ничего писать не нужно, всё есть в комплекте. Я проверил на чистом сайте, у меня всё из коробки завелось без проблем. Посмотрите может есть какие-то ошибки? Попробуйте установить версию 1.0.2.(доступна по ссылке в конце поста)
Хм, походу я криворучко или праздники сказываются, даже авторизация не работает.
Модхост сейчас поднял
s31388.h10.modhost.pro/
Простой пользователь
test@test.ru
123123123
админский
s31388.h10.modhost.pro/manager/
s31388
AzbNTYpnYF11
Модхост сейчас поднял
s31388.h10.modhost.pro/
Простой пользователь
test@test.ru
123123123
админский
s31388.h10.modhost.pro/manager/
s31388
AzbNTYpnYF11
Ну так-то, конечно не работает))) Ты указал, что имя пользователя надо брать из поля email, а имя пользователя у тебя не равно email.
а, да) Я просто копирнул из примеров) Вызывал сомнение этот параметр, но не трогал)
Сейчас все норм и сохраняется, а сохраняется наверно потому что, я до этого под админом открывал сайт, т.е. не был авторизирован в контексте)
Спасибо Артур! буду дальше тестировать :)
Сейчас все норм и сохраняется, а сохраняется наверно потому что, я до этого под админом открывал сайт, т.е. не был авторизирован в контексте)
Спасибо Артур! буду дальше тестировать :)
Подскажите как правильно прописать проверку заполненности множественного поля checkbox?
Вот мое поле из формы:
Вот мое поле из формы:
<div class="pole pole-checkbox">
<div class="pole-label">Тип помещения <span class="error_floor">[[+fi.error.room]]</span></div>
<input type="hidden" name="room[]" value="" data-afl-required="room"/>
<div class="pole-checkbox-item">
<input id="room_1" type="radio" name="room[]" value="Квартира" [[!+fi.room:FormItIsChecked=`Квартира`]] >
<label for="room_1">Квартира</label>
</div>
<div class="pole-checkbox-item">
<input id="room_2" type="radio" name="room[]" value="Частный дом" [[!+fi.room:FormItIsChecked=`Частный дом`]]>
<label for="room_2">Частный дом</label>
</div>
<div class="pole-checkbox-item">
<input id="room_3" type="radio" name="room[]" value="Гостиница" [[!+fi.room:FormItIsChecked=`Гостиница`]]>
<label for="room_3">Гостиница</label>
</div>
<div class="pole-checkbox-item">
<input id="room_4" type="radio" name="room[]" value="Коммерческое помещение" [[!+fi.room:FormItIsChecked=`Коммерческое помещение`]]>
<label for="room_4">Коммерческое помещение</label>
</div>
</div>
в стиппете указываю валидатор:'validate' => 'room:minValue=^1^',
'room.vTextMinValue' => 'Выберите значение.'
На выходе валидация не работает, при отправке формы ошибки в консоли
если использую просто room:required — то все равно ошибка в консоли вылетает, как только валидатор по этому полю убираю — форма работатет
Предположу, что разметка неверная. Не вижу контрольного поля и атрибута data-afl-required
присутствует:
<input type="hidden" name="room[]" value="" data-afl-required="room"/>
Понятно. Смысл в том, что пустое поле типа checkbox не передается на сервер, поэтому нужно создать другое поле типа hidden и проверять именно его, а чтобы значение в поле типа hidden менялось нужно в атрибуте data-afl-required указать имя проверяемого поля. Т.е. должно быть так
<div class="pole pole-checkbox">
<div class="pole-label">Тип помещения <span class="error_floor">[[+fi.error.room]]</span></div>
<input type="hidden" name="room-control" value=""/>
<div class="pole-checkbox-item">
<input id="room_1" type="radio" name="room[]" value="Квартира" data-afl-required="oom-control" [[!+fi.room:FormItIsChecked=`Квартира`]] >
<label for="room_1">Квартира</label>
</div>
<div class="pole-checkbox-item">
<input id="room_2" type="radio" name="room[]" value="Частный дом" data-afl-required="oom-control" [[!+fi.room:FormItIsChecked=`Частный дом`]]>
<label for="room_2">Частный дом</label>
</div>
<div class="pole-checkbox-item">
<input id="room_3" type="radio" name="room[]" value="Гостиница" data-afl-required="oom-control" [[!+fi.room:FormItIsChecked=`Гостиница`]]>
<label for="room_3">Гостиница</label>
</div>
<div class="pole-checkbox-item">
<input id="room_4" type="radio" name="room[]" value="Коммерческое помещение" data-afl-required="oom-control" [[!+fi.room:FormItIsChecked=`Коммерческое помещение`]]>
<label for="room_4">Коммерческое помещение</label>
</div>
</div>
А в вызове'validate' => 'room-control:minValue=^1^',
'room-control.vTextMinValue' => 'Выберите значение.'
Спасибо, завтра попробую
Валидация полей заработала. Все супер-пупер =)
Подскажите как закрыть окно после отправки формы?
Для минишоп можно как то сделать что бы сообщения подтягивались с вашего дополнения?
Для минишоп можно как то сделать что бы сообщения подтягивались с вашего дополнения?
Компонент генерирует JS событие afl-complete. Повесьте на него обработчик, в котором вызовите метод закрытия окна.
Для минишоп можно как то сделать что бы сообщения подтягивались с вашего дополнения?Не совсем понятно, что имеется в виду, но предположим, что речь об уведомлениях. Если вы используете новый комплект JS скриптов, то там точно такие же уведомления. Если используете стандартный, то нужно переопределить объект Message.
import AflIziToast from './../components/ajaxformitlogin/js/modules/aflizitoast.class.js';
document.addEventListener('DOMContentLoaded', (e) => {
if (typeof miniShop2 !== 'undefined') {
miniShop2.Message = new AflIziToast({
"jsPath": "assets/components/ajaxformitlogin/js/lib/izitoast/iziToast.min.js",
"cssPath": "assets/components/ajaxformitlogin/css/lib/izitoast/iziToast.min.css",
"handlerClassName": "iziToast",
"handlerOptions": {
"timeout": 2000,
"position": "topCenter"
}
});
}
});
Если не будет работать используйте задержку через setTimeout, поскольку при импорте скрипт должен быть type=«module», а скрипты этого типа всегда грузятся асинхронно.
А куда это прописать что бы переопределить?
Если скрипты ваши подключаются без type=«module», то в отдельный файл.
К сожалению не работает. Встроенные сообщения выводятся.
Значит что-то не так. Смотрите ошибки в консоли, если их нет, логируйте процесс самостоятельно.
Спасибо.
Если для поля установлено несколько валидаторов, например:
name.vTextRequired и name.vTextMinLength
То при незаполненном поле — показывается текст ошибки и с первого валидатора со второго валидатора, хотя до него еще не дошли. Это можно поправить?
Те. если поле не заполнено — показываем name.vTextRequired, если заполнено мало, то name.vTextMinLength
name.vTextRequired и name.vTextMinLength
То при незаполненном поле — показывается текст ошибки и с первого валидатора со второго валидатора, хотя до него еще не дошли. Это можно поправить?
Те. если поле не заполнено — показываем name.vTextRequired, если заполнено мало, то name.vTextMinLength
Немного не по адресу вопрос, за валидацию отвечает FormIt.
Интересно то, что если я исполню сниппет AjaxForm то такой проблемы не возникает
Скиньте вызов, я посмотрю. А вообще, AjaxForm точно так же работает, показывает все ошибки сразу.
отбой, не в то поле смотрел. от сниппета не зависит
Продолжаю разбираться с компонентом, делаю регистрацию.
Пользователь создается, на почту приходит письмо с ссылкой для активации (ссылка ведет на главную с ключом).
Перехожу по ней, просто открывается главная.
Проверяю юзера в админке — он все также не активирован. Не пойму как настроить активацию
Сниппет aflActivateUser, куда его ставить, в чем его функция?
Пользователь создается, на почту приходит письмо с ссылкой для активации (ссылка ведет на главную с ключом).
Перехожу по ней, просто открывается главная.
Проверяю юзера в админке — он все также не активирован. Не пойму как настроить активацию
Сниппет aflActivateUser, куда его ставить, в чем его функция?
Функция сниппета aflActivateUser в том, чтобы активировать аккаунт пользователя. Ставить его надо на ту страницу, на которую ведёт ссылка активации.
Ага, не сразу нашел этот параметр.
Теперь ссылка открывает страницу активации, но при переходе на страницу по ссылке — страница как то рушится, половина страницы не рендерится, а в коде куча такого: «ignore_e1c06d85ae7b8b032bef47e42e4c08f9»
Сама страница стандартная, на ней только:
Теперь ссылка открывает страницу активации, но при переходе на страницу по ссылке — страница как то рушится, половина страницы не рендерится, а в коде куча такого: «ignore_e1c06d85ae7b8b032bef47e42e4c08f9»
Сама страница стандартная, на ней только:
{set $user = '!aflActivateUser' | snippet:[]}
{if $user}
<h2>Уважаемый, {$user.username}, Ваш аккаунт успешно активирован!</h2>
{/if}
Из-за чего это может быть, а пользователь не активируется при этом
Не знаю. В таких случаях смотрят логи и потом думают, как это исправить.
В том то и дело, что там пусто (в логах MODX).
в консоли браузера, появляется ошибка:
Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
в консоли браузера, появляется ошибка:
Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
Ну кроме логов Modx, есть ещё логи сервера.
При стандартных параметрах (только адрес отправителя меняю и ID страницы подтверждения)
При отправке формы регистрации:
все поля принимают disabled
magazin.ru.xsph.ru/assets/components/ajaxformitlogin/action.php 500 (Internal Server Error)
В логах сервера:
При отправке формы регистрации:
все поля принимают disabled
magazin.ru.xsph.ru/assets/components/ajaxformitlogin/action.php 500 (Internal Server Error)
В логах сервера:
[u][13/Mar/2023:12:05:38 +0300] 0.214 0.250 500 141.8.197.42 magazin.ru POST /assets/components/ajaxformitlogin/action.php HTTP/1.0 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36" "http://magazin.ru.xsph.ru/lk/registracziya" 282 141.8.195.33 a0454867
Это не тот лог, там ошибка должна быть.
после 30-й попытке, я все таки поймал ошибку, указывающую на обязательное поле, которого не было в форме.
я его добавил, письмо для подтверждения улетело. Перехожу по ссылке, а на странице подтверждения следующий прикол:
пол страницы отрезано, все начина с {set $user = '!aflActivateUser' | snippet:[]}
В консоли ошибка:
/lk/confirmation?lu=YWRtOTNydXNAeWFuZGV4LnJ1 500 (Internal Server Error)
Если этот сниппет убрать, страница загружается нормально.
Вобще вкурить не могу, что я делаю не правильно…
я его добавил, письмо для подтверждения улетело. Перехожу по ссылке, а на странице подтверждения следующий прикол:
пол страницы отрезано, все начина с {set $user = '!aflActivateUser' | snippet:[]}
В консоли ошибка:
/lk/confirmation?lu=YWRtOTNydXNAeWFuZGV4LnJ1 500 (Internal Server Error)
Если этот сниппет убрать, страница загружается нормально.
Вобще вкурить не могу, что я делаю не правильно…
В логе ошибок сервера должна быть информация о том, где и какая ошибка.
Там то что по ошибке 500 только то, что я выше писал.
Вобщем решил эксперименты отложить до лучших времен, когда потребность будет, пока вернул Login в работу. С ним проблем не возникает.
Вобщем решил эксперименты отложить до лучших времен, когда потребность будет, пока вернул Login в работу. С ним проблем не возникает.
Дайте доступы в админку. сюда t.me/ShevArtV мне самому интересно в чём там проблема
Ок, завтра. А то все спят
Выкатил обновление с исправлением вашей проблемы.
Есть какая-нибудь информация по срокам появления поддержки modx3? Спасибо
Надеюсь скоро. Я задумал масштабное обновление, думаю под это дело сделаю и адаптацию. Ориентировочно 1-2 месяца
Ребята, подскажите, как правильно настроить скрипт, что бы он срабатывал только при отправке определенной формы, например у которай есть data атрибу post (к примеру)
Сейчас у меня такой скрипт, он срабатывает на все формы:
Сейчас у меня такой скрипт, он срабатывает на все формы:
document.addEventListener('afl_complete', e => {
if (e.detail.response.success) {
тут что должно происзодить
}
});
я хочу на формы регистрации и.т.п. сделать один уведомления, а на заявки другие
Не знаю правильно я сделал или нет, но работает такой способ:
в transmittedParams в success добавил параметр post
ниже его вызвал 'post' => 'true',
И в самом скрипте смотрим был этот параметр вызван или нет
в transmittedParams в success добавил параметр post
ниже его вызвал 'post' => 'true',
И в самом скрипте смотрим был этот параметр вызван или нет
document.addEventListener('afl_complete', e => {
if (e.detail.response.data.post) {
тут что должно произойти
}
});
В целом, можно и так, но проще добавить id самой форме и проверять его, ведь есть e.detail.form, который содержит DOMElement формы.
Если почтовых форм несколько на странице, то придется проверять несколько ID.
Если несколько, можно добавить общий класс и проверять его.
Можешь пример подсказать?
document.addEventListener('afl_complete', e => {
if (e.detail.form.classList.contains('some-class-name')) {
тут что должно произойти
}
});
Ну и в чанке формы<form class="some-class-name">
...
</form>
Спасибо!
Почему может не отрабатывать параметр spamProtection?
В вызове он включен, но приходит спам, если посмотреть форму через FormIT, то там поле aflsecret пустое, как понимаю, форма не должна отправляться если оно пустое?
В вызове он включен, но приходит спам, если посмотреть форму через FormIT, то там поле aflsecret пустое, как понимаю, форма не должна отправляться если оно пустое?
Не знаю, надо логгировать процесс.
Подскажите, почему можете не работать валидация select?
форма:
форма:
<form action="{$_modx->resource.id | url}" method="post" enctype="multipart/form-data">
<input type="hidden" name="page" value="{$_modx->resource.pagetitle | htmlent}">
<div class="form">
<div class="pole pole-icon">
<input type="tel" name="phone" placeholder="Ваш телефон" autocomplete="off">
<span class="error-info error_phone"></span>
</div>
<div class="pole pole-icon">
<input type="text" name="name" placeholder="Как Вас зовут?" autocomplete="off">
<span class="error-info error_name"></span>
</div>
<div class="pole">
<select name="otdel">
<option disabled selected value="">Выбор отдела*</option>
<option value="Сервис"[[!+fi.otdel:FormItIsSelected=`Сервис`]]>Сервис</option>
<option value="Запчасти"[[!+fi.otdel:FormItIsSelected=`Запчасти`]]>Запчасти</option>
<option value="Автомобили"[[!+fi.otdel:FormItIsSelected=`Автомобили`]]>Автомобили</option>
</select>
<span class="error-info error_otdel"></span>
</div>
<div class="pole pole-btn">
<button type="submit" class="btn bg"><span>Свяжитесь со мной</span></button>
</div>
</div>
<div class="police">
«я ознакомлен(-а) и принимаю условия публичной оферты и даю согласие на обработку персональных данных на условиях»
</div>
</form>
вызов:{'!AjaxFormitLogin' | snippet : [
'form' => 'tpl_form_popup',
'emailTpl' => 'tpl_email',
'snippet' => 'FormIt',
'hooks' => 'FormItSaveForm,email',
'emailTo' => $_modx->config.email_address,
'emailFrom' => $_modx->config.emailsender,
'formName' => 'Заявка на консультацию с сайта ' ~ $_modx->config.site_name,
'emailSubject' => 'Заявка на консультацию с сайта ' ~ $_modx->config.site_name,
'successMessage' => '',
'clearFieldsOnSuccess' => 1,
'transmittedParams' => ["success" => 'ym_goal', "error" => 'aliases'],
'aliases' => 'phone==Телефон,name==Имя',
'showUploadProgress' => 1,
'spamProtection' => 1,
'ym_goal' => 'FORM_GOAL',
'validate' => 'otdel:required,name:required:minLength=^5^,phone:required:minLength=^18^',
'validationErrorMessage' => 'Исправьте, пожалуйста, ошибки!',
'otdel.vTextRequired' => 'Выберите отдел',
'name.vTextRequired' => ' ',
'name.vTextMinLength' => 'Слишком короткое ФИО.',
'phone.vTextRequired' => ' ',
'phone.vTextMinLength' => 'Слишком короткий телефон.',
'secret.vTextContains' => 'Кажется Вы робот. Если это не так, обновите страницу.',
]}
Временно решил проблему убрав disabled у первого option
<option disabled selected value="">Выбор отдела*</option>
Из-за атрибута disabled и не работала, ведь значение с этим атрибутом не может быть выбрано, значит всегда выбрано другое значение, значит оно всегда есть, значит валидатор всегда возвращает true.
Ну с AjaxFormit как раз с disabled работало, это позволяло в select показать подсказку, которую нельзя выбрать.
Поэтому тут бился в стену какое то время =)
Поэтому тут бился в стену какое то время =)
Валидацией занимается FormIt, а мой компонент просто обёртка, такая же как AjaxForm, поэтому и там бы это не работало.
Хз, но на другом сайте где стоит AjaxFormit + Formit там с disabled работает.
Ссылка на этот сайт есть?
да, сейчас в телегу скину
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.