Очень простой способ обработки ajax запросов в MODx Revolution

Все привет, много уже было написано про обработку ajax запросов на фронтенд части сайта в MODx Revolution, есть даже несколько готовых дополнений.
В свою очередь, я хочу предложить ещё один, очень простой способ обработки ajax запросов в MODx Revolution.

Для начала создадим плагин под названием ajaxReqeust, со следующим содержимым:
<?php
if ($modx->event->name == 'OnLoadWebDocument') {
    if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
        $modx->resource->set('cacheable', 0);
        $modx->resource->set('template', 0);
    }
}


Плагин должен срабатывать на системное событие «OnLoadWebDocument».
Данный плагин позволит нам выполнять ajax запросы к ресурсам и получать в ответ только содержимое, без шаблона.
Всё что от нас требуется — это сохранить нужный сниппет или чанк в контент ресурса.

В качестве примера, рассмотрим процесс обработки формы, отправленной посредством ajax запроса.

Создадим новый ресурс с любыми данными, в поле контент введём стандартный вызов сниппета FormIt:
<div id="feedback_form">
    <h2>Форма обратной связи</h2>
    [[!request? &k=`success` &toPlaceholder=`success`]]
    [[+success:is=``:then=`
        [[!FormIt? 
            &hooks=`email,redirect`
            &redirectTo=`[[*id]]`
            &redirectParams=`{"success":"1"}`
            &emailTpl=`feedbackEmailTpl`
            &emailSubject=`Новый вопрос с сайта [[++site_name]]`
            &emailTo=`info@unicontent-studio.ru`
            &emailFrom=`noreply@unicontent-studio.ru`
            &emailFromName=`[[++site_name]]`
            &validate=`
                name:required:stripTags,
                email:email:required,
                message:required:stripTags
            `
            &clearFieldsOnSuccess=`1`
            &validationErrorMessage=`Возникли ошибки при отправке сообщения.`
        ]]

        <form data-target="#feedback_form" class="ajax-form" action="[[~[[*id]]]]" method="POST">
            <div>
                <label>Имя:</label>
                <input type="text" value="[[!+fi.name]]" name="name" />
                [[!+fi.error.name]]
            </div>
            <div>
                <label>E-mail:</label>
                <input type="text" value="[[!+fi.email]]" name="email" />
                [[!+fi.error.email]]
            </div>
            <div>
                <label>Сообщение:</label>
                <textarea name="message">[[!+fi.message]]</textarea>
                [[!+fi.error.message]]
            </div>
            <input type="submit" name="submit" value="Отправить" />
        </form>
    `:else=`
        <p>Ваше сообщение успешно отправлено.</p>
    `]]
</div>


Создадим небольшой сниппет под названием request, который позволит нам вывести сообщение, в случае успешной отправки формы:
<?php
$result = isset($_REQUEST[$k])? strip_tags($_REQUEST[$k]) : '';
if (!empty($toPlaceholder)) {
    $modx->toPlaceholder($toPlaceholder, $result);
}
else {
    return $result;
}


Всё что нам осталось сделать — это подключить небольшой jQuery код в страницу, на которую будет выводиться форма.
Данный скрипт сабмитит форму посредством ajax запроса и обрабатывает полученный ответ:
$(document).ready(function() {
    $('body').on('submit', '.ajax-form', function(e) {
        e.preventDefault();
        var target = this;
        if ($(this).data('target') != undefined) {
            target = $(this).data('target');
        }
        values = $(this).serializeArray();
        $(this).find('input[type="submit"]').attr('disabled', 'disabled');
        $.ajax({
            type: 'POST',
            dataType: 'html',
            url: $(this).attr('action'),
            data: values,
            success: function(data) {
                $(target).replaceWith(data);
            }
        });
    });
});


Вот пожалуй и всё, просто не правда ли?
Больше ничего делать не нужно, никаких дополнительных скриптов, коннекторов и процессоров, всего один небольшой плагин, а обо всём остальном за нас позаботится MODx.
Чанки и сниппеты будут обрабатываться так, как это делается при обычных запросах, то есть никаких хаков для обработки тегов MODx не нужно, ответ приходит уже обработанный парсером.
На этом всё, надеюсь моя небольшая статья сделает жизнь кому-то чуточку легче.
Удачи всем и до новых встреч.
Поделиться публикацией
Похожие публикации
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 23
    0
    Статья действительно сделала мне чуточку легче. Спасибо!
      0
      А зачем мы отключаем кеширование?
      А способ действительно зачётный. Главное чтобы не появился… Кто-нибудь, кто будет говорить, что плагины не нужны. :)
        0
        Кеширование отключаем, чтобы при открытии ресурса посредством обычного запроса, он отображался с установленным шаблоном, в некоторых случаях может понадобиться.
          0
          Просто выходит получается серьёзное ограничение на этот метод — без кеширования он уже не столь хорош…
          Кхм, я просто давно с MODX-ом не работал (кстати, X у него большая, раньше маленькая была, а теперь большая в названии), а нельзя ли тот же флаг темплейта возвращать обратно после выполнения парсинга? У него же эвентов для плагинов куча… Чтобы кеширование не отключать.
            0
            Не очень понял вопрос, но суть в том, что в случае с не отключённым кешированием при ajax запросе, ресурс закешируется без шаблона, и при просмотре такого ресурса в браузере, пользователь увидит его кешированную версию, то есть без шаблона и наоборот.
            Данный способ особенно удобен например для ajax пагинации по каталогу товаров, при переходе на следующую страницу возвращает только следующие n товаров, но при открытии страницы в браузере пользователь увидит её полную версию.
              0
              Да ещё кое что, может это не очень логично, но ресурс мы не сохраняем, при просмотре из браузера он закешируется, а вот в случае ajax запроса, пользователь получит некешированную версию и только контент.
                0
                То есть дефакто при доступе через AJAX вы даёте некешируемые данные? Как-то это не очень хорошо…
                  0
                  Да, данные отдаются некешируемые, с другой стороны если речь идёт о доступе к каким-то динамическим данным (например в случае с постраничной разбивкой) или обработке форм, то кешировать там особенно нечего.
                  С другой стороны, всегда можно подключить кеширование непосредственно в плагине, если это необходимо.
          0
          Может, я что-то не понимаю, но разве параметр «HTTP_X_REQUESTED_WITH» веб-сервер гарантировано предоставляет?
            0
            Он предоставляется скорее клиентом. И да, его может не быть. Правда, в данном случае о его наличии заботится jQuery, насколько я это понимаю.
            0
            Можно попробовать и другой мой компонент — AjaxSnippet.

            Его можно вызывать кэшированным, вот документация.
              0
              Приведённый сниппет возможно использовать в случае необходимости сделать ajax форму обратной связи или авторизации?
                0
                Для этого лучше использовать AjaxForm, насколько я могу судить, он работает примерно так же, как описано у вас в посте, только без получения контента ресурса.

                А вот AjaxSnippet нужен для запуска произвольных сниппетов после загрузки страницы. Это позволяет ускорить открытие страницы за счет того, что всё не особо важное (последние комментарии, новости, твиты и т.п.) грузится позже.

                Вместе эти 2 компонента позволяют сделать очень многое.
                  0
                  В примере показана только работа с формами, этот же способ можно использовать для получения результата работы отдельного сниппета или чанка, для этого достаточно добавить в приведённый в начале поста плагин пару условий.
                  Например, можно сделать ajax пагинатор, модифицируя код плагин следующим образом:
                  <?php
                  if ($modx->event->name == 'OnLoadWebDocument') {
                      if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
                          if (isset($_GET['page'])) {
                              $items = $modx->runSnippet('getPage', array(
                                  'element' => 'getResources',
                                  'tpl' => 'rowTpl'
                              ));
                              $modx->resource->set('content', $modx->toJSON(array(
                                  'items' => $items,
                                  'pages' => $modx->getPlaceholder('pageNavVar')
                              )));
                          }
                          $modx->resource->set('cacheable', 0);
                          $modx->resource->set('template', 0);
                      }
                  }
                  

                  При этом один и тот же плагин позволяет как работать с формами, так и получать отдельные элементы.
                    0
                    И в AjaxSnippet, и в AjaxForm можно указать любой сниппет для работы, с произвольным кодом и функциональностью.

                    Но это неважно, потому что собственный велосипед всегда лучше и удобнее. Удачи!
              0
              >>Создадим новый ресурс с любыми данными, в поле контент введём стандартный вызов сниппета FormIt…

              Негоже в поле контент делать такие сложные вызовы снипетов. Вот ещё вариант: modx.com/extras/package/ajaxsubmit (в описании есть ссылка на документацию). Там нет ни сниппета, ни плагина, только запрос нужно отправлять на определенный адрес. Чем хуже ваших с Безумкиным велосипедов?
                0
                Извиняюсь не туда отписал, ответ ниже.
                0
                В чём сложность приведённого сниппета и чем плох вариант с помещением вызова сниппета или чанка в поле контент ресурса?
                Ваш способ ничем не хуже, просто я решил поделиться с сообществом своим опытом.
                В моём примере используется всего один небольшой плагин, что по моему мнению гораздо проще в реализации, да и процесс обработки запроса более прозрачен, запрашиваешь ресурс через ajax, а в ответ получаешь только контент, всё просто и понятно и не нужно разбираться как работают сторонние модули.
                  0
                  >> В чём сложность приведённого сниппета и чем плох вариант с помещением вызова сниппета или чанка в поле контент ресурса?

                  Плох тем, что контент-менеджер сайта может там что-то испортить, вызовы сниппетов ему видеть не надо. Нужно стараться их делать только в шаблонах и чанках. Хотя можно вызов сниппета убрать в чанк. Но если захочется всё-таки сделать вызов сниппета в шаблоне, то ваш способ не подходит.

                  >>да и процесс обработки запроса более прозрачен

                  Тут согласен, ваше решение самое простое и прозрачное, хоть и имеет ограничение, о котором сказал выше.
                    0
                    Подходит и для шаблонов, только в этом случае придётся создать отдельный шаблон и в плагин прописать условие, по которому шаблон ресурса изменится не на 0, а на нужный
                  0
                  Такой вопрос, а что мешает обработать запрос прямо в плагине?
                    0
                    Ничего не мешает — это вопрос удобства использования и поддержки, никаких особенных ограничений нет.
                    Мне удобнее размещать логику в плагине если нужно запустить какой-то код с разными условиями для многих ресурсов.
                    С другой стороны, если это уникальное действие для которого можно выделить отельный ресурс (например форма обратной связи или регистрации), то удобнее размещать в ресурсе.
                      0
                      Да, это логично, просто тогда не ясно зачем ставить еще какие то решения если сам ajax запрос обрабатывает один плагин, спасибо за статью

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое