Иногда стоит задача реализовать AJAX загрузку контента с сервера без перезагрузки страницы. Например, обновить комментарии или подгрузить полный текст статьи при клике на кнопку «Подробнее». Для этого в jQuery есть удобный метод jQuery load(). Он делает асинхронный запрос на сервер и вставляет полученные данные (HTML разметку) в указанный элемент.

$("#result").load("ajax.html");

Вторым аргументом можно передавать параметры запроса

$("#result").load("ajax.php",{param1: value1, param2: value2});

Давайте посмотрим как он работает.

Предположим у нас есть страница с новостями, на которой выводится анонс этих новостей. В конце анонса располагается ссылка «Подробнее» на полный текст новости. Выглядеть это может, например, так.

При клике на ссылку в определенный блок должна подгрузиться вся новость полностью. Вот так выглядит ссылка

<a class="read-more" data-id="5" href="#">Подробнее</a>

где data-id="5" — это id страницы новости. У каждой новости он будет свой.

А сам контент полной новости выводится в блок div, который расположен в конце страницы.

<div id="content"></div>

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


Шаг 1. Контроллер для AJAX запросов

Создадим файл, на который будем отправлять AJAX запрос и который будет возвращать контент указанной страницы. Назовем его ajax.php и положим в папку assets.

<?php
// Если запрос не AJAX или не передано действие, выходим
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' || empty($_REQUEST['action'])) {exit();}

$action = $_REQUEST['action'];

define('MODX_API_MODE', true);
require_once dirname(dirname(__FILE__)).'/index.php';

$modx->getService('error','error.modError');
$modx->getRequest();
$modx->setLogLevel(modX::LOG_LEVEL_ERROR);
$modx->setLogTarget('FILE');
$modx->error->message = null;

$output = '';
switch ($action) {
    case 'getContent':
        // Если не передан id страницы, тоже выходим
        $id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0;
        if (empty($id)) {
            exit();
        };

        $object = $modx->getObject('modResource',$id);
        $output = $object->get('content');
        // Парсим теги MODX
        $maxIterations= (integer) $modx->getOption('parser_max_iterations', null, 10);
        $modx->getParser()->processElementTags('', $output, false, false, '[[', ']]', array(), $maxIterations);
        $modx->getParser()->processElementTags('', $output, true, true, '[[', ']]', array(), $maxIterations);
}


@session_write_close();
exit($output);

Шаг 2. Скрипт обработки

Теперь нам нужно сделать так, чтобы по клику на ссылку «Подробнее» на наш коннектор пошёл AJAX запрос. Сделаем это с помощью jQuery. Создадим файл скрипта и подключим его на странице.

// jQuery должен быть уже подключен
$(document).on('click','.read-more',function(e){
	e.preventDefault();
	var id = $(this).data('id') || 0;
	// Вставляем полученный контент в HTML блок с id="content"
	$("#content").load("/assets/ajax.php",{action:"getContent", id:id});
});

Вот и всё. Если запрос прошел успешно, то в блок с id="content" вставится содержание, которое возвращается из коннектора.


Пример для модального окна

Давайте на практике попробуем использовать данный прием для вывода контента в модальное окно. Опять же воспользуемся фреймворком Bootstrap. В нём уже есть модальные окна.

Добавим в футер разметку модального окна

<div class="modal fadeIn" id="mymodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" aria-label="Close"><span aria-hidden="true">×</span></button>
            <h4 class="modal-title" id="myModalLabel">Модальное окно</h4>
        </div>
        <div id="content" class="modal-body"></div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default btn-close">Закрыть</button>
        </div>
    </div>
  </div>
</div>

Открывать модальное окно мы будем при условии, что контент новости не пустой, т.е. что-то вернётся. А проверять наличие контента мы будем с помощью третьего агрумента функции .load(url, data, complete). Javascript код будет выглядеть так

$(document).on('click','.read-more',function(e){
    e.preventDefault();
    var id = $(this).data('id') || 0;
    // Вставляем контент в тело модального окна
    $("#content").load("/assets/ajax.php",{action:"getContent",id:id}, function(response){
        // Если ответ не пустой, открываем модальное окно
        if (response) {
            $("#mymodal").modal('show');
        }
    });
});

Напоследок

Ну и в конце хочу отметить интересную возможность метода load(). В отличие от других методов он позволяет фильтровать полученный контент с помощью CSS селекторов. Т.е. если нам нужен не весь контент, а только блок с комментариями с id="comments", то указываем это в запросе.

$("#result").load("ajax.php #comments");
22 декабря 2015, 09:12   10237     23

Комментарии ()

  1. Виталий Греков 27 декабря 2015, 20:37 # 0
    Скажите, а как быть если надо чтобы отдало все стили, если применяешь такую конструкцию
    $("#result").load("ajax.php #comments");
    какой в этом случае должен быть php файл и Javascript код, или к примеру передать весь чанк с стилями и может даже с вызовом снипетов.
    У меня получилось воспроизвести работу решения, а начинаю добавлять другие поля типа «pagetitle» или вообще свойство твара «color» и стопорюсь
    1. Сергей Шлоков 27 декабря 2015, 22:40 # 0
      Для таких случаев нужно использовать $.post. Вот тут я писал пример.
      1. Сергей Шлоков 28 декабря 2015, 09:45 # +1
        Сегодня завтра постараюсь написать отдельную статью про обработку данных используя ajax метод $.post().
      2. eminov.eldar 08 апреля 2017, 12:13 # 0
        Большое спасибо автору статьи.
        Только при нажатии кнопки подробнее кирилический текст отображается кракозябрами
        1. Monika 21 ноября 2017, 13:06 # 0
          Спасибо за статью.
          Есть ресурс Портфолио(3). И дочерние ресурсы(36), (46)-Проекты. Они будут добавляться постоянно.
          На ресурсе Портфолио нужно вывести картинки-preview, по клику на которые в модальном окне показывается содержимое ресурса-проекта в виде слайдера.
          В шаблоне Портфолио [[!getResources? &resources=`36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60` &tpl=`clickImage` &limit=`70` &sortby=`{«publishedon»:«ASC»,«createdon»:«ASC»}` &includeTVs=`1` &processTVs=`1` &includeContent=`1` &showHidden=`1`]]

          Чанк `clickImage`
          [[+tv.alt]]
          [[+tv.textClick]]

          [[+tv.clickImage]] и [[+tv.textClick]] — доп поля в ресурсах шаблон Проекты.
          В ресурсах шаблона Проекты отлично выводятся все слайдеры с помощью Migx+Flexslider.
          На ресурсе Портфолио выводятся картинки-preview.
          Делаю, все, как у вас написано, но по клику, в блок id=«comments» ничего не добавляется. Ошибок в консоли тоже нет.
          Как все-таки вывести эти слайдеры дочерних страниц в модальном окне?
          1. Сергей Шлоков 21 ноября 2017, 14:29 # 0
            Значит где-то вы допустили ошибку. Еще раз всё проверьте. У вас слайдер выводится в блок «comments»?

            П.С. Код лучше оборачивать в тег code. Обратите внимание насколько это выглядит читабельнее в статье.
            1. Monika 21 ноября 2017, 16:11 # 0
              Спасибо за ответ, про code не подумала, исправляюсь)
              Уже раз 5 проверила все — при клике пустой:
              <div id="content" class="modal-body"></div>
              Сделано так:
              Шаблон Портфолио
              <section><h1>[[*longtitle:default=`[[*pagetitle]]`]]</h1>        
              <div class="column">[[*content]]</div>
              <div class="column">[[!getResources? &resources=`36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60` &tpl=`clickImage` &limit=`70` &sortby=`{"publishedon":"ASC","createdon":"ASC"}` &includeTVs=`1` &processTVs=`1` &includeContent=`1` &showHidden=`1`]]
              </div>
              </section>
              </div>
              </div>
              <div class="footerbl">
                  [[$rekvizitBlock]]
                  [[$footerBlock]]
              <div class="modal fadeIn" id="mymodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                <div class="modal-dialog" role="document">
                  <div class="modal-content">
                      <div class="modal-header">
                          <button type="button" class="close" aria-label="Close"><span aria-hidden="true">?</span></button>
                          <h4 class="modal-title" id="myModalLabel">Модальное окно</h4>
                      </div>
                      <div id="content" class="modal-body"></div>
                      <div class="modal-footer">
                          <button type="button" class="btn btn-default btn-close">Закрыть</button>
                      </div>
                  </div>
                </div>
              </div>
              </div>
              Чанк clickImage:
              <a class="read-more" data-id="[[+id]]" href="#" title="[[+pagetitle]]"><div class="pic"><img src="[[+tv.clickImage]]" alt="[[+tv.alt]]" />
              <div class="textup">[[+tv.textClick]]</div>
              </div></a> 
              Шаблон Проект
              <section>
              <h1>[[*longtitle:default=`[[*pagetitle]]`]]</h1>   
              <div class="column">[[*content]]</div>
              <div id="comments">[[$hiddenSlider]]</div>
              </div></section>
              Чанк hiddenSlider
              <div class="hiddenbl"><div class="flexslider"><ul class="slides portfolio-slider">[[getImageList?
                  &tvname=`slider`
                  &tpl=`@CODE:
                  <li>
                      <div class="titlebl">[[+set]]</div>
                      <div class="desctitle">[[+description]]</div>
                      <img src="[[+image]]" />
                  </li>`
              ]]
              </ul></div>
              </div>
              файл контроллера положен в папку assets/ajax.php
              скрипт помещен в assets/js/script.js
              $(document).on('click','.read-more',function(e){
                  e.preventDefault();
                  var id = $(this).data('id') || 0;
                  // Вставляем контент в тело модального окна
                  $("#content").load("/assets/ajax.php #comments",{action:"getContent",id:id}, function(response){
                      // Если ответ не пустой, открываем модальное окно
                      if (response) {
                          $("#mymodal").modal('show');
                      }
                  });
              });
              Все переменные, которые учавствуют в сриптах на местах. Ссылки на странице Портфолио имеют вид
              <a class="read-more" data-id="36" href="#" title="Вегас"><div class="pic"><img src="manager/templates/default/images/portfolio/vegas/0.jpg" alt="">
              <div class="textup">Вегас..</div>
              </div></a>
              <a class="read-more" data-id="37" href="#" title="Baden"><div class="pic"><img src="manager/templates/default/images/portfolio/baden/0.jpg" alt="">
              <div class="textup">Baden...</div>
              </div></a>
              а все равно не открывается((( Почему?
              :a
              1. Сергей Шлоков 21 ноября 2017, 16:27 # 0
                Вы фильтруете ответ
                 $("#content").load("/assets/ajax.php #comments"...
                
                В полученном ответе ищется HTML элемент с id=«comments». Так задумано? Он у вас есть?
                1. Monika 21 ноября 2017, 16:36 # 0
                  В идеале — да, элемент с id=«comments»
                  Находится в каждом дочернем шаблоне Проект:
                  <div id="comments">[[$hiddenSlider]]</div>  
                  Более того, ничего не выводится, даже если его убрать совсем:
                  $(document).on('click','.read-more',function(e){
                      e.preventDefault();
                      var id = $(this).data('id') || 0;
                      // Вставляем контент в тело модального окна
                      $("#content").load("/assets/ajax.php",{action:"getContent",id:id}, function(response){
                          // Если ответ не пустой, открываем модальное окно
                          if (response) {
                              $("#mymodal").modal('show');
                          }
                      });
                  }); 
                  1. Сергей Шлоков 21 ноября 2017, 16:46 # 0
                    Боюсь, что поможет только отладка. Удалённая диагностика крайне непродуктивна. Если сами в этом не очень разбираетесь, то попробуйте обратиться к спецам. Это можно сделать на modx.pro
          2. Евгений 11 марта 2018, 17:14 # 0
            Добрый день, Сергей, подскажите пожалуйста в чем может быть ошибка, сделал все как указанно на сайте, но по клику на кнопку подробное, выдает ошибку POST localhost/assets/ajax.php 404 (Not Found)?
            1. Сергей Шлоков 11 марта 2018, 20:40 # 0
              Здравствуйте!
              Если возникает ошибка, значит что-то сделали не так. Для начала попробуйте обратиться к файлу напрямую. А в файле в первой строке укажите
              echo 'Запрос прошел';
              Указанное сообщение должно появиться на странице.
            2. Вадосс 09 апреля 2018, 07:54 # 0
              Доброе утро, подскажите пожалуйста как можно поменять вот этот путь /assets/ajax.php на /assets/components/php/podgruzka-kontenta-ajax.php пробовал разные пути но нечего не помогает?
              1. Сергей Шлоков 09 апреля 2018, 08:43 # 0
                Приветствую!
                Путь указывается в функции load()
                $("#content").load("/assets/ajax.php",{action:"getContent",id:id}, function(response){ ... });
                
                1. Вадосс 09 апреля 2018, 08:59 # 0
                  <script>$(document).on('click','.read-more',function(e){ e.preventDefault(); var id = $(this).data('id') || 0; $("#content-2").load("/assets/components/php/podgruzka-kontenta-ajax.php #comments",{action:"getContent",id:id},function(response){ if (response) { $("#ajax-modal").modal('show'); } }); }); </script>
                  Сергей спасибо что помогаете!
                  Именно так и делаю, а толку ноль. А когда /assets/podgruzka-kontenta-ajax.php так то работает, почему сам понять не могу
                  1. Сергей Шлоков 09 апреля 2018, 11:19 # 0
                    Возможно пути указаны неверно или прав нет. Проверьте ответ от сервера.
              2. Вадосс 09 апреля 2018, 09:27 # 0
                Сергей а подскажите пожалуйста как можно сделать на одной странице сайта, вывод нескольких разных блоков с одного ID по двум разным ссылкам что бы одна выводила #comments-1, а другая #comments-2

                <a class="read-more" data-id="5" href="#">Подробнее</a>
                <a class="read-more" data-id="5" href="#">Подробнее</a>
                $("#content").load("/assets/ajax.php #comments-1",{action:«getContent»,id:id}, function(response){… });
                $("#content").load("/assets/ajax.php #comments-2",{action:«getContent»,id:id}, function(response){… });
                1. Сергей Шлоков 09 апреля 2018, 11:28 # +1
                  Так делать ни в коем случае нельзя. Запрос должен быть один. И в данном случае лучше использовать другие методы — get() или post(). Нужно просто отфильтровать ответ
                  $(response).find('#comments-1').appendTo('#content').end().find('#comments-2').appendTo('#content');
                  
                2. Al 18 апреля 2018, 08:41 # 0
                  Здравствуйте

                  Подскажите пожалуйста, почему не подгружаются данные из тегов на странице? *pagetitle и другие
                  1. Сергей Шлоков 18 апреля 2018, 09:48 # 0
                    К большому сожалению не владею сверхспособностями.
                    1. Al 18 апреля 2018, 09:53 # 0
                      А они здесь требуются?) В контенте на страничке стоит тег *pagetitle, но при загрузке через ajax он не выводится. Другие данные выводятся, а он нет. Просто не понятно почему так происходит.
                      1. Al 18 апреля 2018, 18:45 # +1
                        Для обработки тегов со звёздочкой ресурс должен быть добавлен в $modx.
                        $modx->resource = $modx->getObject('modResource',$id);
                        $output = $modx->resource->get('content');  
                        // Парсим теги MODX
                        ...
                        
                        Только не забудьте добавить проверку существования ресурса перед работой со свойствами.
                        1. Al 18 апреля 2018, 18:45 # 0
                          Спасибо вам.

                          И прошу прощения. Вместо стрелки вверх промахнулся на минус… плохо что не отменяются.

                  Вы должны авторизоваться, чтобы оставлять комментарии.

                  Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.