MODX. AjaxForm обработка форм с использованием Ajax
Отредактировано: 12 Июля 2023
AjaxForm это надстройка для компонента FormIt, которая позволяет отправлять результаты форм используя ajax (можно использовать не только FormIt, но и другие скрипты). Для перехода с FormIt на AjaxForm достаточно изменить запись вызова
[[!AjaxForm?
&snippet=`FormIt` // указываем сниппет который должен вызывать AjaxForm
&form=`tpl.form.feedback` // указываем шаблон формы
... // остальные строки вызова FormIt
]]
Этапы создания Ajax формы на сайте:
- Устанавливаем компоненты FormIt и AjaxForm.
- Создаем чанк с HTML формой и модификаторами.
- Размещаем вызов в соответствующем ресурсе или шаблоне.
Стандартная форма обратной связи
[[!AjaxForm?
&snippet=`FormIt`
&form=`tpl.form.feedback`
&emailTpl=`mailtpl.feedback`
&hooks=`email,spam,FormItSaveForm`
&spamCheckIp=`true`
&emailFrom=`info@domain.ru`
&emailSubject=`Письмо с сайта domain.ru`
&emailTo=`info@domain.ru`
&validate=`name:required,email:email:required,message:required`
&validationErrorMessage=`Не заполненны все необходимые поля`
&successMessage=`Сообщение успешно отправлено`
]]
// содержимое чанка tpl.form.feedback
<form action="" method="post">
<label for="name">Имя*</label>
<input id="name" name="name" value="[[!+fi.name]]">
<label for="email">Email*</label>
<input id="email" name="email" value="[[!+fi.email]]">
<label for="message">Сообщение*</label>
<textarea id="message" name="message" value="[[!+fi.message]]"></textarea>
<input class="btn gradient-border" type="submit" value="Отправить сообщение">
[[!+fi.validation_error_message:!empty=`
<div class="alert">
<p>Пожалуйста, исправьте следующие ошибки:</p>
<ul>
[[!+fi.error.name:!empty=`<li><a href="notes/web/back-end/modx/formit/#name">Поле «Имя» не заполнено</a></li>`]]
[[!+fi.error.email:!empty=`<li><a href="notes/web/back-end/modx/formit/#email">Поле «Email» не заполнено</a></li>`]]
</ul>
</div>`]]
</form>
// чанк mailtpl.feedback
<p>Имя: [[+name]]</p>
<p>Email: [[+email]]</p>
<p>Телефон: [[+phone]]</p>
<p>Сообщение: [[+message]]</p>
В AjaxForm есть дефолтный вид всплывающих окон об успешной отправке и ошибках, чтобы его изменить, надо указать собственные файлы в параметрах frontend_js и frontend_css.
Пример файла без jGrowl, со статичным сообщением во всплывающем окне с id massage
var AjaxForm = {
initialize: function (afConfig) {
if (!jQuery().ajaxForm) {
document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.form.min.js"><\/script>');
}
$(document).off('submit', afConfig['formSelector']).on('submit', afConfig['formSelector'], function (e) {
$(this).ajaxSubmit({
dataType: 'json',
data: {pageId: afConfig['pageId']},
url: afConfig['actionUrl'],
beforeSerialize: function (form) {
form.find(':submit').each(function () {
if (!form.find('input[type="hidden"][name="' + $(this).attr('name') + '"]').length) {
$(form).append(
$('<input type="hidden">').attr({
name: $(this).attr('name'),
value: $(this).attr('value')
})
);
}
})
},
beforeSubmit: function (fields, form) {
//noinspection JSUnresolvedVariable
if (typeof(afValidated) != 'undefined' && afValidated == false) {
return false;
}
form.find('.error').html('');
form.find('.error').removeClass('error');
form.find('input,textarea,select,button').attr('disabled', true);
return true;
},
success: function (response, status, xhr, form) {
form.find('input,textarea,select,button').attr('disabled', false);
response.form = form;
$(document).trigger('af_complete', response);
if (!response.success) {
if (response.data) {
var key, value, focused;
for (key in response.data) {
if (response.data.hasOwnProperty(key)) {
if (!focused) {
form.find('[name="' + key + '"]').focus();
focused = true;
}
value = response.data[key];
form.find('.error_' + key).html(value).addClass('error');
form.find('[name="' + key + '"]').addClass('error');
}
}
}
}
else {
form.find('.error').removeClass('error');
form[0].reset();
//noinspection JSUnresolvedVariable
if (typeof(grecaptcha) != 'undefined') {
//noinspection JSUnresolvedVariable
grecaptcha.reset();
}
$('.overlay').fadeIn('fast', function () {
$('#message').animate({
'top': '50%'
}, 500);
});
}
}
});
e.preventDefault();
return false;
});
$(document).on('keypress change', '.error', function () {
var key = $(this).attr('name');
$(this).removeClass('error');
$('.error_' + key).html('').removeClass('error');
});
$(document).on('reset', afConfig['formSelector'], function () {
$(this).find('.error').html('');
AjaxForm.Message.close();
});
}
};
Пример файла с редиректом после успешной отправки
var AjaxForm = {
initialize: function (afConfig) {
if (!jQuery().ajaxForm) {
document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.form.min.js"><\/script>');
}
if (!jQuery().jGrowl) {
document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.jgrowl.min.js"><\/script>');
}
$(document).ready(function () {
$.jGrowl.defaults.closerTemplate = '<div>[ ' + afConfig['closeMessage'] + ' ]</div>';
});
$(document).off('submit', afConfig['formSelector']).on('submit', afConfig['formSelector'], function (e) {
$(this).ajaxSubmit({
dataType: 'json',
data: {pageId: afConfig['pageId']},
url: afConfig['actionUrl'],
beforeSerialize: function (form) {
form.find(':submit').each(function () {
if (!form.find('input[type="hidden"][name="' + $(this).attr('name') + '"]').length) {
$(form).append(
$('<input type="hidden">').attr({
name: $(this).attr('name'),
value: $(this).attr('value')
})
);
}
})
},
beforeSubmit: function (fields, form) {
//noinspection JSUnresolvedVariable
if (typeof(afValidated) != 'undefined' && afValidated == false) {
return false;
}
form.find('.error').html('');
form.find('.error').removeClass('error');
form.find('input,textarea,select,button').attr('disabled', true);
return true;
},
success: function (response, status, xhr, form) {
form.find('input,textarea,select,button').attr('disabled', false);
response.form = form;
$(document).trigger('af_complete', response);
if (!response.success) {
AjaxForm.Message.error(response.message);
if (response.data) {
var key, value, focused;
for (key in response.data) {
if (response.data.hasOwnProperty(key)) {
if (!focused) {
form.find('[name="' + key + '"]').focus();
focused = true;
}
value = response.data[key];
form.find('.error_' + key).html(value).addClass('error');
form.find('[name="' + key + '"]').addClass('error');
}
}
}
}
else {
AjaxForm.Message.success(response.message);
form.find('.error').removeClass('error');
form[0].reset();
//noinspection JSUnresolvedVariable
if (typeof(grecaptcha) != 'undefined') {
//noinspection JSUnresolvedVariable
grecaptcha.reset();
}
//редиректим на страницу
document.location.href = "http://адрес/для/редиректа"
}
}
});
e.preventDefault();
return false;
});
$(document).on('keypress change', '.error', function () {
var key = $(this).attr('name');
$(this).removeClass('error');
$('.error_' + key).html('').removeClass('error');
});
$(document).on('reset', afConfig['formSelector'], function () {
$(this).find('.error').html('');
AjaxForm.Message.close();
});
}
};
//noinspection JSUnusedGlobalSymbols
AjaxForm.Message = {
success: function (message, sticky) {
if (message) {
if (!sticky) {
sticky = false;
}
$.jGrowl(message, {theme: 'af-message-success', sticky: sticky});
}
},
error: function (message, sticky) {
if (message) {
if (!sticky) {
sticky = false;
}
$.jGrowl(message, {theme: 'af-message-error', sticky: sticky});
}
},
info: function (message, sticky) {
if (message) {
if (!sticky) {
sticky = false;
}
$.jGrowl(message, {theme: 'af-message-info', sticky: sticky});
}
},
close: function () {
$.jGrowl('close');
},
};
Настройка целей для счетчиков
Отслеживать успешную отправку формы, без изменения кода компонента можно добавив перехватчик в сообщение об успешной отправке:
&successMessage=`Ваше письмо успешно отправлено <script>yaCounterXXXXXXXX.reachGoal('form');</script>`
Документация сниппета AjaxForm
AjaxForm
AjaxForm
Внимание
13 июня 2023 года команда MODX RSC прекратила поддержку AjaxForm. Он будет продолжать быть доступным на маркетплейсах modstore.pro и extras.modx.com, но мы рекомендуем использовать вместо него компонент FetchIt.
Cниппет для отправки любых форм через ajax. По умолчанию рассчитан на работу с FormIt, но можно использовать и собственный сниппет.
- Регистрирует нужные скрипты на фронтенде: jQuery.Form и jQuery.jGrowl.
- Сохраняет в сессию
$scriptProperties
при вызове сниппета. - Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения
$scriptProperties
. - Вешает обработчик на форму, чтобы она отправлялась через ajax.
- При отправке запускает указанный сниппет для обработки и возвращает ответ от него.
- Выводит сообщение об успехе, или ошибки, если есть.
Параметры сниппета
Имя | По умолчанию | Плейсхолдеры |
---|---|---|
&form | tpl.AjaxForm.example |
Образец чанка с формой, которую нужно обработать. |
&snippet | FormIt |
Сниппет для обработки формы. |
&frontend_css | [[+assetsUrl]]css/default.css |
Стили оформления формы и полей с ошибками |
&frontend_js | [[+assetsUrl]]js/default.js |
Javascript для отправки формы через ajax |
&actionUrl | [[+assetsUrl]]action.php |
Адрес коннектора, на который отправляется форма |
Всё, что вы указываете AjaxForm, будет передано в вызываемый сниппет.
Обработка своим сниппетом
Вы можете использовать собственный сниппет, вместо FormIt, который будет делать что угодно (хоть создавать страницы на сайте). Единственное требование - он обязательно должен возвращать JSON массив с ключами:
- status — 1 или 0, то есть успех или ошибка.
- message — сообщение о работе сниппета, выводится если status = 0.
- data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке.
Для удобства работы в параметры сниппета передаётся переменная $AjaxForm
с классом компонента, чтобы вы могли вызывать из него методы error и success при выдаче ответа.
Простейший пример своего сниппета:
<?php
if (empty($_POST['name'])) {
return $AjaxForm->error('Ошибки в форме', array(
'name' => 'Вы не заполнили имя'
));
}
else {
return $AjaxForm->success('Форма прошла проверку');
}
<?php
if (empty($_POST['name'])) {
return $AjaxForm->error('Ошибки в форме', array(
'name' => 'Вы не заполнили имя'
));
}
else {
return $AjaxForm->success('Форма прошла проверку');
}
Вызываем так:
[[!AjaxForm?
&snippet=`MySnippet`
&form=`tpl.AjaxForm.example`
]]
[[!AjaxForm?
&snippet=`MySnippet`
&form=`tpl.AjaxForm.example`
]]
Этот сниппет ничего не делает, просто возвращает результат проверки имени.
Валидация формы
Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку. Этим полям автоматически будет добавлен CSS класс error
, который убирается при последующей отправке.
Так же вы можете запретить отправку формы, используя javascript переменную afValidated - если она объявлена и равна false
, то форма не будет отправлена.
Обратите внимание, что все проверки на javascript можно обойти, так что эту переменную стоит использовать только для удобства пользователей, а не для реальной проверки данных.
<script type="text/javascript">
$(document).on('submit', '.ajax_form', function() {
// Здесь любой код для проверки формы при отправке
// Я просто печатаю её в консоли бразуреа
console.log(this);
// Результатом работы будет выставление глобальной переменной
afValidated = false; // Или true, если валидация пройдена
});
</script>
[[!AjaxForm]]
<script type="text/javascript">
$(document).on('submit', '.ajax_form', function() {
// Здесь любой код для проверки формы при отправке
// Я просто печатаю её в консоли бразуреа
console.log(this);
// Результатом работы будет выставление глобальной переменной
afValidated = false; // Или true, если валидация пройдена
});
</script>
[[!AjaxForm]]
Событие af_complete
При получении ответа от сервера вызывается событие af_complete, которое вы можете использовать для обновления содержимого страницы или другой операции javascript.
Вам просто нужно указать функцию, в которую будет передано событие javascript и объект с ответом от сервера. Обратите внимание, что внутри этого объекта есть и отправляющая форма.
$(document).on('af_complete', function (event, response) {
var form = response.form;
// Если у формы определённый id
if (form.attr('id') === 'my_form_3') {
// Скрываем её!
form.hide();
}
// Иначе печатаем в консоль весь ответ
else {
console.log(response)
}
});
$(document).on('af_complete', function (event, response) {
var form = response.form;
// Если у формы определённый id
if (form.attr('id') === 'my_form_3') {
// Скрываем её!
form.hide();
}
// Иначе печатаем в консоль весь ответ
else {
console.log(response)
}
});
redirect на другую страницу сайта, после успешной отправки формы?
Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки
$(document).on('af_complete', function (event, response) {
var form = response.form;
if (form.attr('id') === 'значение id формы') {
window.location.href = "[[~id страницы]]"
}
});
$(document).on('af_complete', function (event, response) {
var form = response.form;
if (form.attr('id') === 'значение id формы') {
window.location.href = "[[~id страницы]]"
}
});
Можно просто обернуть в <script>
выше приведенный код</script>
и подключить в шаблон с формой ближе к закрытию body.
Всплывающие сообщения
По умолчанию AjaxForm выводит сообщения об успешной отправке формы или о наличии ошибок. Вы можете самостоятельно вызывать их для своих целей:
AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');
AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');
Вторым параметром можно указать «прилипающий» popup — его нужно будет закрыть вручную, бывает полезно для показа серьёзных ошибок.
То есть, просто вызвав сниппет на странице, вы получаете подключенный jQuery.jGrowl и можете показывать приятные всплывающие уведомления на javascript.
Примеры
Отправка email сообщения при помощи FormIt с требованием некоторых полей:
[[!AjaxForm?
&snippet=`FormIt`
&form=`tpl.AjaxForm.example`
&hooks=`email`
&emailSubject=`Тестовое сообщение`
&emailTo=`info@domain.com`
&validate=`name:required,email:required,message:required`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено`
]]
[[!AjaxForm?
&snippet=`FormIt`
&form=`tpl.AjaxForm.example`
&hooks=`email`
&emailSubject=`Тестовое сообщение`
&emailTo=`info@domain.com`
&validate=`name:required,email:required,message:required`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено`
]]
Отладка
При возникновении любых проблем, в первую очередь проверяйте, отправляется ли форма без AjaxForm. Помните, что AjaxForm - сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.
Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript. Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP - он должен быть отключен.