MODX AjaxForm — документация и примеры построения контактных форм

MODX AjaxForm - документация и примеры построения контактных форм MODX Revo

В прошлом уроке мы разобрали документация по пакету FormIt и построили сложную форму. Сегодня логическое продолжение и в данной уроке мы рассмотрим компонент AjaxForm — сниппет для отправки форм через ajax, который по умолчанию рассчитан на работу с пакетом FormIt, но можно написать собственный обработчик.

Установить AjaxForm можно через репозиторий modstore.

AjaxForm vs FormIt — что лучше использовать. Плюсы и минусы.

Мне не нравится что аякс форм, при инициализации регистрирует на фронтенде скрипты: jQuery.Form и jQuery.jGrowl. По этому, когда на странице 1 форма, я обычно использую чистый FormIt, т.к. он не добавляет своих библиотек. Когда на странице по 3-10 форм (это сейчас модно), я всегда использую AjaxForm, т.к. нет проблем с отправкой (дублированием писем) с разных форм + есть дополнительные плюшки.

  • Сохраняет в сессию $scriptProperties при инициализации сниппета.
  • Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения $scriptProperties.
  • Вешает обработчик для отправки форм через ajax — без перезагрузки страницы.
  • При отправке запускает указанный вами сниппет (обработчик) и возвращает ответ от него.
  • Выводит сообщение об успехе отправки, или ошибки.

Документация по AjaxForm

Основные параметры

Имя По умолчанию Плейсхолдеры и примечания
&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 выводит сообщения об успешной отправке формы или о наличии ошибок. Можете самостоятельно вызывать их для своих целей:

AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');

Указав второй параметр (, 1) — вы получаете «прилипающий» popup, который не закрывается автоматически (а только по нажатию на крестик) — бывает полезно для показа серьёзных ошибок.

примеры всплывающих сообщений с AjaxForm

За выплывающие уведомления, отвечает подключаемая по умолчанию  javascript библиотека jQuery.jGrowl.

Обработка своим сниппетом

Хотите вместо 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('Форма прошла проверку');
}

Примечание: данный сниппет ничего не делает, просто возвращает результат проверки имени.

Вызываем так:

[[!AjaxForm?
    &snippet=`MySnippet`
    &form=`tpl.AjaxForm.example`
]]

Валидация формы

Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку. Этим полям автоматически будет добавлен CSS класс error, который убирается при последующей отправке.

Так же вы можете запретить отправку формы, используя javascript переменную afValidated — если она объявлена и равна false, то форма не будет отправлена.

Важно! Все проверки на javascript можно обойти, так что лучше не использовать эту переменную стоит использовать для реальной проверки данных. Используйте только для удобства пользователей.

<script>
$(document).on('submit', '.ajax_form', function() {
    // Здесь любой код для проверки формы при отправке
    console.log(this);

    // Результатом работы будет выставление глобальной переменной
    afValidated = false; // Или true, если валидация пройдена
});
</script>

Событие 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)
    }
});

Пример с оф. документации

Отправка 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. Помните, что AjaxForm — сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.

Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript. Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP — он должен быть отключен.

Официальная документация по компоненту AjaxForm.

Реальные примеры создания форм обратной связи

Стоит 2 задачи, рассмотрим их.

Задача 1. Создать форму заказа обратного звонка в модальном окне.

Форма должна выполнять следующее:

  • сохранять данные в админке MODX;
  • поле ввода телефона должно быть по маске;
  • после успешной отправки должно выводиться сообщение: «Спасибо за обращение в нашу компанию! Менеджер свяжется с вами в ближайшее время»;
  • модальное окно после отправки формы должно закрываться.

Решение.

Т.к. сайт собран на bootstrap 4, возьмем стандартную разметку модального окна и формы. Конечная HTML разметка получилась такой.

<a href="javascript:void(0)" data-toggle="modal" data-target="#zakazat-zvonok">Заказать звонок</a>

<form class="obr-zvonok" action="#" method="post">
    <div class="form-group">
        <input type="text" class="form-control" placeholder="Ваше имя" aria-describedby="name" required>
    </div>
    <div class="form-group">
        <input type="text" id="phone" class="form-control" placeholder="Ваш телефон" aria-describedby="phone" required>
    </div>
    <div class="form-group form-check">
        <input type="checkbox" class="form-check-input" checked required>
        <label class="form-check-label small" for="policy">Согласен на <a href="#" target="_blank" rel="noopener noreferrer">обработку персональных данных</a>.</label>
    </div>
    <button type="submit" class="btn btn-primary center">Отправить</button>
</form>

Маску ввода сделаем при помощи jQuery библиотеки maskedinput, на этом останавливаться не буду смотрите урок: Маска ввода для полей HTML форм на jQuery.

Теперь разметим форму атрибутами name — это обязательно, пример:

<input type="text" class="form-control" name="name" placeholder="Ваше имя" aria-describedby="name" required>

здесь атрибут required — делает поле обязательным.

Далее в action желательно добавить URL адрес страницы сайта, в form добавить дополнительный класс ajax_form af_example и можно поместить ее в чанк obr-zvonok.

Конечный код чанка obr-zvonok.

<form class="obr-zvonok ajax_form af_example" action="[[~[[*id]]? &scheme=`full`]]" method="post">
    <div class="form-group">
        <input type="text" class="form-control" name="name" placeholder="Ваше имя" aria-describedby="name" required>
    </div>
    <div class="form-group">
        <input type="text" id="phone" class="form-control" name="phone" placeholder="+7 (___) ___-__-__" aria-describedby="phone" required>
    </div>
    <div class="form-group form-check">
        <input type="checkbox" class="form-check-input" checked required>
        <label class="form-check-label small" for="policy">Согласен на <a href="[[~12]]" target="_blank" rel="noopener noreferrer">обработку персональных данных</a>.</label>
    </div>
    <button type="submit" class="btn btn-primary center">Отправить</button>
[[+fi.success:is=`1`:then=`<div class="alert alert-success">[[+fi.successMessage]]</div>`]]
</form>

Делаем вызов формы

[[!AjaxForm? 
    &snippet=`FormIt` 
    &form=`obr-zvonok`
    &hooks=`email`
    &emailTpl=`tpl-form` 
    &emailTo=`[[++emailsender]]`
    &emailSubject=`Заказ звонка с [[++site_url]]` 
    &successMessage=`<p class="h4">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>` 
]]

Чтобы форма начала сохранятся в админке нам нужно добавить хук FormItSaveForm, указать название формы (formName), перечислить поля, которые нужно сохранить (formFields) и названия полей (fieldNames), в итоге получаем следующий вызов.

AjaxForm на fenom

Чанк с формой на fenom.

<form class="obr-zvonok ajax_form af_example" action="{$_modx->makeUrl($_modx->resource.id, '', '', 'full')}" method="post">
    <div class="form-group">
        <input type="text" class="form-control" name="name" placeholder="Ваше имя" aria-describedby="name" required>
    </div>
    <div class="form-group">
        <input type="text" id="phone3" class="form-control" name="phone" placeholder="+7 (___) ___-__-__" aria-describedby="phone" required>
    </div>
    <div class="form-group form-check">
        <input type="checkbox" class="form-check-input" checked required>
        <label class="form-check-label small" for="policy">Согласен на <a href="{$_modx->makeUrl(13)}" target="_blank" rel="noopener noreferrer">обработку персональных данных</a>.</label>
    </div>
    <button type="submit" class="btn btn-primary center">Отправить</button>
{if $fi.success = 1}{$fi.successMessage}{/if}
</form>

Вызов формы на fenom.

{'!AjaxForm' | snippet : [
    'snippet' => 'FormIt',
    'form' => 'obr-zvonok',
    'emailTpl' => 'tpl-form',
    'hooks' => 'email,FormItSaveForm',
    'emailFrom' => $_modx->config.emailsender,
    'fromName' => 'Заказ звонка',
	'formFields' => 'name,phone',
	'fieldNames' => 'name==Имя,phone==Телефон',
    'emailSubject' => 'Сообщение с сайта' ~ $_modx->config.site_name,
    'emailTo' => $_modx->config.emailsender,
    'successMessage' => '<p class="h4">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>',
]}

Задача 2. Продвинутая форма с вложениями при помощи Formit + AjaxForm

Будем создавать вот такую форму.

Продвинутая форма с вложениями при помощи Formit + AjaxForm

По сути она достаточно простая. но ее особая особенность. это вложения.

И так. данная форма имеет, вот такой html код:

<form class="ajax_form" method="post" action="" enctype="multipart/form-data">
 <fieldset>
  <div class="row"> 
   <div class="col-sm-4">  
    <div class="fancy-form">
	<i class="fa fa-user"></i>
	<input type="text" name="name" required="" class="form-control" placeholder="Ваше имя*" value="">
    </div>
   </div>
   <div class="col-sm-4"> 
    <div class="fancy-form">
	<i class="fa fa-at"></i>
	<input type="text" name="email" required="" class="form-control" placeholder="Ваш email*" value="">
    </div>
   </div>
   <div class="col-sm-4"> 
    <div class="fancy-form">
	<i class="fa fa-phone"></i>
	<input type="text" class="form-control" id="pfone" name="pfone" required="" placeholder="Ваш телефон*" value="">
    </div>
   </div>
  </div>
  <div class="fancy-form bottom-21">
	<select class="form-control pointer" name="department">
		<option value="">--- Выберите тип работы ---</option>
		<option value="Разработка-сайта-под-ключ">Разработка сайта под ключ</option>
		<option value="Доработка-сайта">Доработка сайта</option>
		<option value="Адаптация-имеющегося-сайта">Адаптация имеющегося сайта</option>
		<option value="Разработка-верстка-дизайна-сайта">Разработка/верстка дизайна сайта</option>
		<option value="Продвижение-сайта">Продвижение сайта</option>
		<option value="Рекламные-компании">Рекламные компании</option>
		<option value="Разработка-дизайна-групп">Разработка дизайна групп</option>
		<option value="Продвижение-групп">Продвижение групп</option>
		<option value="Прочее">Прочее</option>
	</select>
  </div>
  <div class="fancy-form bottom-21">
	<textarea rows="5" name="message" required="" class="form-control word-count" data-maxlength="2000" data-info="textarea-words-info" placeholder="Примечания / пожелания"></textarea>
	<i class="fa fa-comments"><!-- icon --></i>
 	<span class="error error_name"></span>
  </div>
  <div class="input-group file-upload w100">
  <div class="input-group"><span class="input-group-addon"><i class="fa fa-paperclip"></i></span><input class="custom-file-upload custom-file-upload-hidden" placeholder="Ваше задание, методичка и т.д.*" type="file" id="file" name="attachment" data-btn-text="Выберите файл" tabindex="-1" style="position: absolute; left: -9999px;"><input type="text" class="form-control file-upload-input text-left"><span class="input-group-btn" tabindex="-1"><button type="button" class="file-upload-button btn btn-primary">Выберите файл</button></span></div>
  </div>
</fieldset>
<button type="submit" class="btn btn-3d btn-xmg btn-primary btn-w100">Отправить</button>
</form>

По сути обычная немного модифицированная bootstrap разметка.

Обязательный атрибут для использования вложений в MODX: enctype=»multipart/form-data»

Ну а теперь ближе к делу:

Создаем чанк, ну к к примеру form-uslugi и помещаем в него весть вышеприведенный код, далее модифицируем его под Formit + AjaxForm, получаем:

<form method="post" action="[[~[[*id]]]]" enctype="multipart/form-data">
    <fieldset>
        <div class="row"> 
            <div class="col-sm-4">  
                <div class="fancy-form">
                	<i class="fa fa-user"></i>
                	<input type="text" name="name" required="" class="form-control" placeholder="Ваше имя*" value="[[+fi.name]]">
                	<span class="error error_name">[[+fi.error.name]]</span>
                </div>
            </div>
            <div class="col-sm-4"> 
                <div class="fancy-form">
                	<i class="fa fa-at"></i>
                	<input type="text" name="email" required="" class="form-control" placeholder="Ваш email*" value="[[+fi.email]]">
                	<span class="error error_name">[[+fi.error.email]]</span>
                </div>
            </div>
            <div class="col-sm-4"> 
                <div class="fancy-form">
                	<i class="fa fa-phone"></i>
                	<input type="text" class="form-control" id="pfone" name="pfone" required="" placeholder="Ваш телефон*" value="[[+fi.pfone]]">
                	<span class="error error_name">[[+fi.error.pfone]]</span>
                </div>
            </div>
        </div>
        <div class="fancy-form bottom-21">
        	<select class="form-control pointer" name="department">
        		<option value="">--- Выберите тип работы ---</option>
        		<option value="Разработка-сайта-под-ключ">Разработка сайта под ключ</option>
        		<option value="Доработка-сайта">Доработка сайта</option>
        		<option value="Адаптация-имеющегося-сайта">Адаптация имеющегося сайта</option>
        		<option value="Разработка-верстка-дизайна-сайта">Разработка/верстка дизайна сайта</option>
        		<option value="Продвижение-сайта">Продвижение сайта</option>
        		<option value="Рекламные-компании">Рекламные компании</option>
        		<option value="Разработка-дизайна-групп">Разработка дизайна групп</option>
        		<option value="Продвижение-групп">Продвижение групп</option>
        		<option value="Прочеее">Прочеее</option>
        	</select>
        </div>
        <div class="fancy-form bottom-21">
        	<textarea rows="5" name="message" required="" class="form-control word-count" data-maxlength="2000" data-info="textarea-words-info" placeholder="Примечания / пожелания"></textarea>
        	<i class="fa fa-comments"><!-- icon --></i>
        	<span class="error error_name">[[+fi.error.message]]</span>
        </div>
        <div class="input-group file-upload w100">
        <input class="custom-file-upload custom-file-upload-hidden" type="file" id="file" name="attachment" data-btn-text="Выберите файл" tabindex="-1" style="position: absolute; left: -9999px;">
        </div>
    </fieldset>
<button type="submit" class="btn btn-3d btn-xmg btn-primary btn-w100">Отправить</button>
[[+fi.success:is=`1`:then=`
<div class="alert alert-success">[[+fi.successMessage]]</div>`]]
[[+fi.validation_error:is=`1`:then=`<div class="alert alert-error">[[+fi.validation_error_message]]</div>`]]
</form>

Далее создаем 2й чанк tpl-form-uslugi, со следующим содержимым

<p>Имя: [[+name]]</p>
<p>Email: [[+email]]</p>
<p>Телефон: [[+pfone]]</p>
<p>Тип работы: [[+department]]</p>
<p>Сообщение: [[+message]]</p>
<p>Файл: [[+attachment]]</p>

Ну и остается лишь только вызвать эту форму в нужном месте.

[[!AjaxForm?
&snippet=`FormIt`
&form=`form-uslugi`
&emailTpl=`tpl-form-uslugi`
&hooks=`spam,email`
&emailSubject=`Сообщение с сайта [[++site_url]]`
&emailTo=`mail@webadaptiv.ru`
&validate=`name:required,email:required`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено!`
]]

Ну и проверяем работоспособность.

проверяем работоспособность форм

Плюшки

Закрываем модальное окно после отправки формы

Нам нужна кнопка закрытия, в моем случае

<button type="button" class="close" data-dismiss="modal" aria-label="Close">
   <span aria-hidden="true">×</span>
</button>

cм. bootstrap modal.

модальное окно

Так вот нам нужен класс элемента, который закрывает форму при клике, в моем случае это кнопка (buttom) с классом close.

Воспользуемся событием af_complete для клика по этой кнопке.

$(document).on('af_complete', function(event,res) {
	if(res.success) $('.close').click();
});

К стати его нужно прописывать в js файл или подключать в шаблон обвертывая в тег <script> </script>

оборачиваем событие в script

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

Изменение стилей и положения всплывающего окна Ajaxform.

AjaxForm для стилизации окон использует стили jGrowl, которые лежат в assets/components/ajaxform/css/lib/jquery.jgrowl.min.css, можно поправить все прямо там, но если вы обновите компонент, то и стили ваши обновятся на дефолтные, следовательно их лучше предопределить в своем css.

К примеру положение окна по дефолту заданно вот таким стилем

.jGrowl.top-right{top:0;right:0}

те прижато к верху и правой стороне.

Чтобы сменить положение, к примеру по центру, достаточно предопредилить их в своем css, к примеру так:

.jGrowl.top-right{top:40% !important;width:30% !important;left:35% !important}

И точно таким же образом можно изменить весь внешний вид окошко с уведомлением, вот мой конечный код для одного из сайтов:

#jGrowl{font-size:18px;margin:0 12px}
.jGrowl.top-right{left:35%!important;top:35%!important}
#jGrowl .jGrowl-notification{position:relative;width:320px;padding:15px;text-align:center;background:none repeat 0 0 #fff!important;box-shadow:0 0 0 7px #8ab933!important;border:0 solid rgba(255,255,255,0.49)!important}
#jGrowl .jGrowl-notification .jGrowl-close{position:absolute;right:4px;top:4px;color:#8ab933!important}
#jGrowl .jGrowl-notification .jGrowl-message{color:#8ab933!important}

в итоге всплывает вот такое окошко по центру сайт.

новый вид уведомляшки в аякс форм

Оптимизация скорости загрузки сайта. 

  1. Делайте вызов Ajaxform кэшированным (без !).
  2. Объедините стандартные стили и скрипты со своими и укажите в вызове чтобы стандартные не подключались.

Берем CSS код из assets/components/ajaxform/css/lib/jquery.jgrowl.min.css,  assets/components/ajaxform/css/default.css и переносим его в общий файл стилей.

объединяем стили

default.css — из этого файла выкидываем верхнюю строку @import url(‘./lib/jquery.jgrowl.min.css’); — т.к. код мы подключили сразу.

Также берем содержимое файла assets/components/ajaxform/js/default.js и объединяем с основным js файлом.

Далее отключаем css и js в вызове ajaxform.

&frontend_css=«
&frontend_js=«

{'!AjaxForm' | snippet : [
    'snippet' => 'FormIt',
    'form' => 'obr-zvonok',
    'emailTpl' => 'tpl-form',
    'hooks' => 'email,FormItSaveForm',
    'emailFrom' => $_modx->config.emailsender,
    'fromName' => 'Заказ звонка',
	'formFields' => 'name,phone',
	'fieldNames' => 'name==Имя,phone==Телефон',
    'emailSubject' => 'Сообщение с сайта' ~ $_modx->config.site_name,
    'emailTo' => $_modx->config.emailsender,
    'successMessage' => '<p class="h4">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>',
    'frontend_css' => '',
    'frontend_js' => ''
]}

redirect на другую страницу сайта, после успешной отправки формы?

Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки

$(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 это добавить в сообщение успешной отправки script

&successMessage=`Сообщение успешно отправлено
                 <script>ga('send', 'event', 'plea', 'button_ok');
                 yaCounterXXXXXXXX.reachGoal('zayavka');</script>`

Как передать адрес и заголовок страницы

<a href="{$pageId | url}">{$pageId | resource : 'pagetitle'}</a>

Если полный адрес не выводится, попробуйте так

<a href="{$pageId | url : ['scheme' => 'full']}">{$pageId | resource : 'pagetitle'}</a>

Чекбокс — согласие с политикой обработки персональных данных

<div class="checkbox">
    <label>
      <input type="checkbox" required checked> Согласен на <a href="/polici" target="_blank">обработку персональных данных</a>
    </label>
</div>

Дополнительно

Сохранение форм в админке, добавление маски ввода для телефона, email, даты идентично formit.

Смотрите также:

Как в MODX Revo избавиться от спама с FormIt, AjaxForm

Google reCAPTCHA(v2) для FormIt и AjaxForm

Алексей

Веб-дизайнер и SEO оптимизатор. Занимаюсь созданием сайтов с 2010 года и их продвижение с 2012 года!

Оцените автора
( Пока оценок нет )
web-revenue.ru
Добавить комментарий

  1. Сергей

    Доброй ночи. Скажите для чего прописывать aria-describedby в формах?
    Заранее спасибо

    Ответить
    1. Алексей автор

      Здравствуйте. https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute

      Ответить