AjaxForm без jQuery
Приветствую тебя дорогой читатель. Давно хотел это сделать и наконец-то сделал — теперь для работы AjaxForm не нужен jQuery.
ТЕПЕРЬ ДЛЯ ЭТОГО НУЖНО ПРОСТО ИСПОЛЬЗОВАТЬ SENDIT
Для этого нужно
1. Перейти по ссылке.
2. Заменить содержимое папок core/components/ajaxform и assets/componentns/ajaxform/ данными из репозитория.
3. Заменить код сниппета AjaxForm кодом из репозитория.
Если будут ошибки пишите в комментарии, а под катом немного о нюансах.
Немного нюансов.
0. В лексиконы добавлены следующие записи
1. Событие af_complete осталось, но теперь доступ к параметрам осуществляется так
4. Параметр clearFieldsOnSuccess точно работает, можно отменять перезагрузку формы, для этого нужно передать false без кавычек.
5. Для показа уведомлений нужно установить SweetAlert2.
6. Назначение некоторых функций осталось для меня загадкой, поэтому я просто переписал их на чистый JavaScript.
UPD от 15.02.22: Добавил ссылку на репозиторий для помощи в поиске ошибок и рефакторинге.
UPD от 07.03.22:
Добавил новые параметры сниппета AjaxForm:
Если в форме есть input[type=«file»]
1. fileUplodedProgressMsg — сообщение, которое будет показано во время загрузки файлов.
2. fileUplodedSuccessMsg — сообщение об успешном завершении загрузки файлов.
3. fileUplodedErrorMsg — сообщение об ошибке при загрузке файлов, не путать с сообщением от валидатора файлов, если такой у вас есть.
4. showUplodedProgress — по умолчанию false, т.е. прогресс загрузки не показывается, если нужно включить показ прогресса ставим true. Соответственно добавлены методы обработки процесса загрузки файлов в default.js, они называются onUploadProgress, onUploadFinished, onUploadError;
Так же в отдельные методы вынес обработку ошибок валидации (onError) и успешной отправки формы (onSuccess).
Всю логику можно переопределить, для этого в конструкторе класса core/components/ajaxform/model/ajaxform/ajaxform.class.php я переопределил конструктор, теперь можно в системные настройки добавить свои пути к стилям и скриптам через настройки af_frontend_css и af_frontend_js соответственно. Правда выпилить стандартные параметры сниппета не могу, поэтому, в целом, данный функционал не работает.
UPD от 09.03.22:
При наличии на странице более одного вызова AjaxForm обязательно указывать параметр formSelector. Он должен быть уникальным для каждой формы, в противном случае каждая форма будет отправляться более 1 раза. Уникальный селектор генерируется автоматически. ВАЖНО! И это не я придумал, селектор это всегда название класса указанное без точки. Если нужно чтобы применились стили по умолчанию в форму руками надо добавить класс ajax_form. Скорее всего я этот момент доработаю, но это неточно.
UPD от 12.03.2022
Класс ajax_form добавляется автоматически ко всем формам.
UPD от 29.04.2022
Нашел способ передавать произвольный обработчик уведомлений. Чтобы добавить свой обработчик нужно создать минимум 1 системную настройку с именем af_message_handler с названием класса обработчика. В этом классе должны быть реализованы методы error, success, close и info. Можно сгруппировать эти методы, как это сделано в SweetAlert2, в этом случае нужно создать ещё одну системную настройку с именем af_message_handler_method где должно быть указано название подметода. Например, если ваш класс выводит сообщение так
Однако, это всё только в теории, на практике я не проверял, но SweetAlert2 работает.
ТЕПЕРЬ ДЛЯ ЭТОГО НУЖНО ПРОСТО ИСПОЛЬЗОВАТЬ SENDIT
Для этого нужно
1. Перейти по ссылке.
2. Заменить содержимое папок core/components/ajaxform и assets/componentns/ajaxform/ данными из репозитория.
3. Заменить код сниппета AjaxForm кодом из репозитория.
Если будут ошибки пишите в комментарии, а под катом немного о нюансах.
Немного нюансов.
0. В лексиконы добавлены следующие записи
$_lang['af_message_uploded_progress'] = 'Загружено: ';
$_lang['af_message_uploded_success'] = 'Данные полностью загружены на сервер!';
$_lang['af_message_uploded_error'] = 'Произошла ошибка при загрузке данных на сервер!';
$_lang['af_message_ajax_error'] = 'Форма не была отправлена! Свяжитесь с администратором.';Первые три параметры отвечают за загрузку файлов, последний будет показан если запрос не попадёт на сервер или если сервер вернёт код ответа не 200.1. Событие af_complete осталось, но теперь доступ к параметрам осуществляется так
document.addEventListener('af_complete', function (e) {
e.detail.status; // статус ответа
e.detail.response; // сам ответ
e.detail.form; // элемент формы
e.detail.xhr; // объект запроса
});2. Событие af_complete можно отменить стандартным способом document.addEventListener('af_complete', function (e) {
e.preventDefault();
// тут кастомный код обработки ответа.
});3.form теперь это обычный элемент DOM полученный через document.querySelector, поэтому и работать с ней нужно как с DOM элементом.4. Параметр clearFieldsOnSuccess точно работает, можно отменять перезагрузку формы, для этого нужно передать false без кавычек.
5. Для показа уведомлений нужно установить SweetAlert2.
6. Назначение некоторых функций осталось для меня загадкой, поэтому я просто переписал их на чистый JavaScript.
UPD от 15.02.22: Добавил ссылку на репозиторий для помощи в поиске ошибок и рефакторинге.
UPD от 07.03.22:
Добавил новые параметры сниппета AjaxForm:
Если в форме есть input[type=«file»]
1. fileUplodedProgressMsg — сообщение, которое будет показано во время загрузки файлов.
2. fileUplodedSuccessMsg — сообщение об успешном завершении загрузки файлов.
3. fileUplodedErrorMsg — сообщение об ошибке при загрузке файлов, не путать с сообщением от валидатора файлов, если такой у вас есть.
4. showUplodedProgress — по умолчанию false, т.е. прогресс загрузки не показывается, если нужно включить показ прогресса ставим true. Соответственно добавлены методы обработки процесса загрузки файлов в default.js, они называются onUploadProgress, onUploadFinished, onUploadError;
Так же в отдельные методы вынес обработку ошибок валидации (onError) и успешной отправки формы (onSuccess).
Всю логику можно переопределить, для этого в конструкторе класса core/components/ajaxform/model/ajaxform/ajaxform.class.php я переопределил конструктор, теперь можно в системные настройки добавить свои пути к стилям и скриптам через настройки af_frontend_css и af_frontend_js соответственно. Правда выпилить стандартные параметры сниппета не могу, поэтому, в целом, данный функционал не работает.
UPD от 09.03.22:
UPD от 12.03.2022
Класс ajax_form добавляется автоматически ко всем формам.
UPD от 29.04.2022
Нашел способ передавать произвольный обработчик уведомлений. Чтобы добавить свой обработчик нужно создать минимум 1 системную настройку с именем af_message_handler с названием класса обработчика. В этом классе должны быть реализованы методы error, success, close и info. Можно сгруппировать эти методы, как это сделано в SweetAlert2, в этом случае нужно создать ещё одну системную настройку с именем af_message_handler_method где должно быть указано название подметода. Например, если ваш класс выводит сообщение так
MessageHandler.success(message);то MessageHandler должно быть значением af_message_handler. Если вывод сообщения происходит такMessageHandler.Method.success(message);то MessageHandler должно быть значением af_message_handle, а Method значением af_message_handler_method.Однако, это всё только в теории, на практике я не проверял, но SweetAlert2 работает.
Комментарии: 62
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Хорошо бы его сначала протестить по-полной, но за решительный шаг, наконец-то избавить компонент от jQuery — уважуха!
Сейчас тестирую скрипт, где-то лезут ошибки в браузер из-за недостающих проверок на существование элементов, что джеквери делает под капотом.
Так же хорошо, что убран функционал с уведомлениями, он должен быть опциональным, но проверки на него тоже выкидывают ошибки в консоль.
Автору благодарность, ошибки не критичные, легко все пофиксить
И я правильно понимаю, что в твоем варианте оригинальный ajaxForm все равно нужно подключать, а потом этой штукой перезаписывать метод initialize?
Да. В идеале сделать pr и из коробки загружать этот код, но для этого нужно его до ума до вести.
2. Старайся использовать const вместо let
3. Я бы заменил XHR на fetch.
4. А разве не должно быть метода error для работы с ошибками?
Success выводит уведомления об успешных транзакциях $ajaxForm->success()
Error соответственно в случае $ajaxForm->error()
По сути использование const не дает никакой выгоды перед let, как это например наблюдается в других языках, где если объявляется константа, то под нее в памяти резервируется минимально необходимое количество байт.
В javascript использование const не более чем попытка пойти по модному течению «сейчас в моде снова языки строгой типизации». Раньше был турбо паскаль, фортран, позже с++, джава в которых нельзя было обьявить переменную не указав точно тип данных, которые мы планируем в ней хранить.
int var x = 5;
Потом мода менялась и стали говорить мол, вот вам новые языки, здесь не нужно думать о типе переменной, творите что хотите, теперь вы свободны и появились php, javascript и прочее.
Сейчас же (лично по моим наблюдениям) новый виток спирали — снова в моду входит строгая типизация. Javascript разрабатывает typescript, php вводит typehinting, позволяет указывать что должна вернуть функция, в общем становится очень похож на с++.
И const в javascript (на мой взгляд) не более чем баловство, ведь работает это только на примитивных данных, а для ссылочных типов данных работает некорректно, тоесть позволяет мутировать объект. Поэтому мне кажется, кому нужна строгая типизация тот пойдет писать на typescript, а остальным без разницы let или const, хотя может я и ошибаюсь.
Или я чего-то не знаю?
Смотри jquery ajax() подписывает свои запросы заголовком X-Requested-With со значением XMLHttpRequest
И многие компоненты, в том числе упомянутый modhelpers просто проверяют наличие заголовка
Выходит Чтобы все серверные скрипты сработали — достаточно передать этот заголовок
В конкретно этом ajaxForm за авторством Артура сделано вот так
Fetch работает точно так же. Нужно передать заголовок. Просто синтаксис чуть другой будет
1. Можно учитывать, что конфиг может по какой-то причине не будет доступен или он придёт неполным
и далее в коде методов ты не будешь париться и обращаться к конфигу так:
2. Обычно принято в мире js передавать селектор первым аргументом, а вторым конфиг плагина, это намного удобнее, и я понимаю, что AjaxForm в оригинале такой и ты просто перевел код, но тут заодно можно и это исправить:
3. У тебя на 20-ой строке есть странность if (this.beforeSubmit(e.target)) { и судя по коду твой метод beforeSubmit всегда возвращает true, тогда я понятия не имею зачем тут проверка.
Если нет формы, то нет смысла и дальше что-то делать. Тут вылез ещё один интересный момент, уже в сниппите. Там есть вот такой кусок кода
По-моему, он устарел, проще прямо в чанк передавать весь конфиг и устанавливать селектор так {$formSelector} или так [[+formSelector]]. Хотя с другой стороны, ну есть и есть, да?
И ещё в оригинальном сниппите сделано вот так
Мне кажется это нелогично, ведь создавая экземпляр класса, мы мерджим дефолтный конфиг и $scriptProperties, т.е. на мой взгляд, в getOption нужно писать так
Или я чего-то не понимаю?
Ну вообще запись станет длиннее this.config.someprop против this.someprop, но я доверюсь твоему опыту.
Тут отдельная проблема. В конструктор надо передавать уникальный селектор, потому что в противном случае если на странице больше 1 вызова AjaxForm обработчики навешиваются столько раз сколько вызывается сниппет, а это плохо по понятным причинам. И передавать селектор в каждом вызове мне кажется неудобным. Я думаю надо установить селектор по умолчанию и дополнять его меткой времени и тоже самое делать с переданным селектором, чтобы на 100% исключить вероятность дублирования или есть варианты решения получше?
Это у меня он возвращает true, а если кто-то захочет свою логику, например не отправлять пока не прочитают политику работы с персональными данными?
Я самоучка, это не оправдание, но что значит пройтись по стандартам не понимаю.
И есть ещё один момент — уведомления
Это я оставил для обратной совместимости, но это объект, мне кажется правильнее было бы сделать показ сообщения методом или методами класса, но как туда впихнуть код выше? Тут предлагали сделать как @Николай Савин в minishop2, но у него это тоже объект. Может уведомления сделать отдельным классом? Добавить из коробки уведомления не требующие jQuery, только вот надо же ещё дать возможность подключать произвольные уведомления, но как это лучше сделать?
А тут самое простое решение, это при навешивании обработчика проверять например css класс af_initialized, а уже после добавить к форме этот класс.
Теперь понял
Это наверное потом, когда вдруг захочешь сделать PR
Я уже скоро захочу, уведомления только прикручу))) Вдруг кому-то ещё надо, чтобы не было jQuery. Или может сделать форк?
Заменил default.js и core/components/ajaxform/model/ajaxform/ajaxform.class.php
При загрузке страницы ошибка:
При отправке происходит перезагрузка страницы. Форма не отправляется, журнал ошибок пуст
Тестировал отправку на Windows, Chrome Android — всё отправляется.
На айфонах (реальных) + тест в Browserstack — форма не отправляется.
По моим наблюдениям в режиме nojq затык происходит в момент отправки запроса: форма будто бы замирает, либо пытаясь отправить данные, либо ожидая ответа от сервера
хотя есть FetchIt (вроде то, что нужно)