Среди огромного многообразия движков сайта особо выделятся такая CMS, как MODx. Чем? Да просто много ли знаете движков, позволяющих человеку, не знающему ничего, кроме HTML, поднять за день сайт? Сайт не плохой, с абсолютно авторским дизайном/вёрсткой, никаких сторонних шаблонов, или, боже упаси, сервисов-конструкторов, и функциональный: генерируемые \"на лету\" меню, формы обратной связи, блог, и даже интернет-магазинчик, достаются парой кликов из обширного репозитория расширений, и гибко настраиваются прямо из админки, про существование PHP знать не обязательно!
Сегодня я поделюсь маленьким лайф-хаком для создания AJAX-приложений в MODx. Да, я знаю про сниппет ajaxForm, и что "правильно" написать на PHP скрипт-контроллер в папке сайта, но "фишка" MODx в том, что для него не надо знать PHP! :-) Так что сделаем всё стандартными для данного движка средствами.
Приступим. Забираем из файла cont_emailForm весь HTML и добавляем в поле "Контент" нашего документа, это обычная bootstrap-вёрстка формы с парой полей, кнопкой отправки сообщения и модальным окном для вывода сообщений. Внизу кода есть пустой тег script весь клиентский код будем писать в нём.
Начинаем наш скрипт, как и любой другой правильный JS, с инкапсуляции всех наших трудов в специальной функции:
(function($){ })(jQuery);
Если неясно, зачем такая загогулина - поясняю: мы прячем область видимости всех наших переменных внутри безымянной функции, и не боимся случайно поломать другие скрипты, переопределив их переменные. Заодно мы сразу вызываем нашу функцию-контейнер передав в неё экземпляр фреймворка jQuery, и гарантируем что в нашем коде значок $ это jQuery, а не какой-нибудь MooTools.
Внутри этой функции первым делом определим адрес для AJAX-запроса:
var customAjaxHandler='/';
Пока просто делаем ссылку на корень сайта, позднее заменим её ссылкой на документ с контроллером.
Далее создадим функцию для валидации e-mail адресов:
function isEmail(email) { var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; return regex.test(email); }
Сильно комментировать её не буду - в ней всю работу делает regex. Если знакомы с регулярными выражениями - всё будет ясно и так, если впервые про них узнали - то это тема для отдельного урока. Короче, наша функция вернёт true если в неё передан валидный e-mail.
Наконец, повесим на нашу формы обработчик события отправки:
$('#ajaxMail').on('submit', function (e) { })
Т.к. нам не требуется обычная отправка формы, блокируем стандартную обработку события:
e.preventDefault();
Сразу после этого, определим несколько переменных нужных для валидации формы:
var form = this, errors = false, errorInput = [];
Даём нашей форме понятный псевдоним form, вместо служебного this определяем флаг наличия ошибок errors, и создаём массив errorInput для хранения ссылок на невалидные поля ввода.
У нас есть только одно поле требующее валидации - почтовый адрес для отправки ответа, проверяем его конструкцией if:
if ( !isEmail(form.elements['email'].value) ) { errors = true; errorInput.push(form.elements['email']); }
Используем нашу функцию isEmail для проверки текущего значения в поле, если с полем что-то не так, переключаем флаг errors в true, и добавляем ссылку на элемент с именем email в массив невалидных элементов.
Следующий этап - обработка всех ошибок в форме: маркировка всех проблемных полей, вывод сообщения пользователю. Используем флаг errors для ветвления алгоритма:
if ( errors ) { errorInput.forEach(function (el) { $(el).closest('.form-group').addClass('has-error'); }); }
Используем метод forEach для перебора всех элементов массива errorInput. forEach - относительно новая фича в javascript, позволяет выполнить определённые действия над каждым элементом массива. Мы помещаем инпут в обёртку jQuery, затем находим ближайший родительский элемент с классом form-group, и добавляем этому элементу класс has-error.
Теперь, если не ввести валидный email в соответствующее поле, оно будет выделено красным при нажатии на кнопку Отправить.
Также стоит сообщить пользователю почему сработал этот "светофор", для этого выведем сообщения в модальном окне, добавив сразу после errorInput.forEach(...)
$('#commonModal .modal-title').html('Внимание!'); $('#commonModal .modal-body').html('Заполните требуемые поля!'); $('#commonModal').modal();
Используем стандартное бутстраповское модальное окно: с помощью $('#commonModal .modal-title').html('Внимание!'); и $('#commonModal .modal-body').html('Заполните требуемые поля!'); изменяем текст заголовка и текста в модалке и открываем её.
С обработкой ошибок закончили, перейдём к отправке запроса. Добавим к if ( errors ) {...}
else { $('.form-group.has-error').removeClass('has-error'); $.ajax({ type: 'POST', url: customAjaxHandler, data: $(form).serialize(), dataType: 'json', success: function(data) { $('#commonModal .modal-title').html(''); $('#commonModal .modal-body').html(data.message); $('#commonModal').modal(); } }); }
Командой $('.form-group.has-error').removeClass('has-error') находим все элементы, отмеченные как ошибочные, и снимаем с них класс has-error, убрав выделение цветом.
И наконец, пишем отправку AJAX-запрса средствами jQuery, передавая следующие опции:
Всё с клиентом закончили, переходим в MODx.
Заходим в админку, создаём новый документ в корне сайта, открываем его для редактирования, даём ему произвольный заголовок, обязательно выставляем пустой шаблон, отмечаем чекбоксы "Не показывать в меню" и "Опубликован", на вкладке "Настройки" указываем JSON как тип содержимого, снимаем чекбоксы "Доступен для поиска", "Использовать HTML-редактор" и "Кэшируемый".
В поле "Содержимое" вводим {"message":"Тест соединения пройден!"}. Сохраняем документ.
Снова открываем документ с нашей формой, находим там строчку var customAjaxHandler='/'; и заменяем '/' на '[[~3]]'. [[~]] это специальный тег MODx, после тильды (~) нужно указать id документа и шаблонизатор подставит УРЛ к документу с данным id. Сохраняем документ с формой, открываем его в браузере (или обновляем если он уже открыт).
Теперь, если всё правильно сделано, при заполнении поля с email и нажатии на кнопку "Отправить" откроется модальное окно с сообщением "Тест соединения пройден!"
Добившись получения этого сообщения и убедившись, что информация приходит по нужному адресу, сделаем что-нибудь полезное. Например, пошлём письмо по введённому email адресу с текстом сообщения из формы.
Воспользуемся для этого сниппетом FormIt. Открываем документ - коннектор, удаляем из него {"message":"Тест соединения пройден!"} и записываем вызов сниппета:
[[!FormIt? &hooks=`FormItAutoResponder` &validate=`email:required:email` &fiarFrom=`norep@modx.roothelp.ru` &fiarFromName=`[[++site_name]]` &fiarSubject=`[[++site_name]] автоответчик` &fiarToField=`email` &fiarTpl=`autoResponse` &successMessage=`{"message":"Сообщение отправлено!"}` ]]
Параметры:
Если валидация будет пройдена, и все хуки успешно отработают, FormIt создаст плейсхолдер с именем fi.successMessage, в котором будет содержаться текст, указанный в параметре successMessage, выводим его сразу после вызова сниппета:
[[!+fi.successMessage:default=`{"message":"Ошибка при отправке!"}`]]
Знаком "!" запрещаем кеширование плейсхолдера, указываем имя самого плейсхолдера, дальше добавим модификатор default. При успешной отправке в плейсхолдере будет json с сообщением, а при неуспешной - плейсхолдер окажется пустым, и ничего не будет отправлено скрипту на нашей страничке. Модификатор решает эту проблему - при неуспехе отправки выводится соответствующее сообщение.
Остался последний штрих - шаблон самого письма. Просто создаём шаблон с именем autoResponse и вводим в нём:
[[+comment:default=`Привет!`]]
Просто выводим значение поля формы с именем comment, обратите внимание, что не требуется отмена кеширования (FormIt и так обновляет этот шаблон при каждой отправке), используем знакомый нам модификатор default для подстановки "запасного" значения в случае если посетитель не ввёл свой текст. Сохраняем шаблон.
Собственно на этом всё, надеюсь этот нехитрый приём окажется полезным.