• Блог
  • Ajax подгрузка контента

Иногда стоит задача реализовать 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");
0   31150

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

  1. Виталий Греков 27 декабря 2015 # 0
    Скажите, а как быть если надо чтобы отдало все стили, если применяешь такую конструкцию
    $("#result").load("ajax.php #comments");
    какой в этом случае должен быть php файл и Javascript код, или к примеру передать весь чанк с стилями и может даже с вызовом снипетов.
    У меня получилось воспроизвести работу решения, а начинаю добавлять другие поля типа «pagetitle» или вообще свойство твара «color» и стопорюсь
    1. Сергей Шлоков 27 декабря 2015 # 0
      Для таких случаев нужно использовать $.post. Вот тут я писал пример.
      1. Сергей Шлоков 28 декабря 2015 # +1
        Сегодня завтра постараюсь написать отдельную статью про обработку данных используя ajax метод $.post().
      2. eminov.eldar 08 апреля 2017 # 0
        Большое спасибо автору статьи.
        Только при нажатии кнопки подробнее кирилический текст отображается кракозябрами
        1. Monika 21 ноября 2017 # 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 # 0
            Значит где-то вы допустили ошибку. Еще раз всё проверьте. У вас слайдер выводится в блок «comments»?

            П.С. Код лучше оборачивать в тег code. Обратите внимание насколько это выглядит читабельнее в статье.
            1. Monika 21 ноября 2017 # 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 # 0
                Вы фильтруете ответ
                 $("#content").load("/assets/ajax.php #comments"...
                
                В полученном ответе ищется HTML элемент с id=«comments». Так задумано? Он у вас есть?
                1. Monika 21 ноября 2017 # 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 # 0
                    Боюсь, что поможет только отладка. Удалённая диагностика крайне непродуктивна. Если сами в этом не очень разбираетесь, то попробуйте обратиться к спецам. Это можно сделать на modx.pro
          2. Евгений 11 марта 2018 # 0
            Добрый день, Сергей, подскажите пожалуйста в чем может быть ошибка, сделал все как указанно на сайте, но по клику на кнопку подробное, выдает ошибку POST localhost/assets/ajax.php 404 (Not Found)?
            1. Сергей Шлоков 11 марта 2018 # 0
              Здравствуйте!
              Если возникает ошибка, значит что-то сделали не так. Для начала попробуйте обратиться к файлу напрямую. А в файле в первой строке укажите
              echo 'Запрос прошел';
              Указанное сообщение должно появиться на странице.
            2. Вадосс 09 апреля 2018 # 0
              Доброе утро, подскажите пожалуйста как можно поменять вот этот путь /assets/ajax.php на /assets/components/php/podgruzka-kontenta-ajax.php пробовал разные пути но нечего не помогает?
              1. Сергей Шлоков 09 апреля 2018 # 0
                Приветствую!
                Путь указывается в функции load()
                $("#content").load("/assets/ajax.php",{action:"getContent",id:id}, function(response){ ... });
                
                1. Вадосс 09 апреля 2018 # 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 # 0
                    Возможно пути указаны неверно или прав нет. Проверьте ответ от сервера.
              2. Вадосс 09 апреля 2018 # 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 # +1
                  Так делать ни в коем случае нельзя. Запрос должен быть один. И в данном случае лучше использовать другие методы — get() или post(). Нужно просто отфильтровать ответ
                  $(response).find('#comments-1').appendTo('#content').end().find('#comments-2').appendTo('#content');
                  
                2. Al 18 апреля 2018 # 0
                  Здравствуйте

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

                          И прошу прощения. Вместо стрелки вверх промахнулся на минус… плохо что не отменяются.
                          1. Игорь 24 октября 2023 # 0
                            Помогите пожалуйста, не получается вывести pagetitle в
                            <h5 class="modal-title" id="orderModalLabel"></h5>
                            <?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;
                            
                            $result = ['content' => '', 'pagetitle' => ''];
                            switch ($action) {
                                case 'getContent':
                                    // Если не передан id страницы, тоже выходим
                                    $id = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
                                    if (empty($id)) {
                                        exit();
                                    }
                            
                                    $resource = $modx->getObject('modResource', $id);
                                    if (!$resource) {
                                        exit('Ресурс не найден');
                                    }
                            
                                    $modx->resource = $resource;
                                    $result['content'] = $resource->get('content');
                                    $result['pagetitle'] = $resource->get('pagetitle');
                            
                                    // Парсим теги MODX
                                    $maxIterations = (integer)$modx->getOption('parser_max_iterations', null, 10);
                                    $modx->getParser()->processElementTags('', $result['content'], false, false, '[[', ']]', [], $maxIterations);
                                    $modx->getParser()->processElementTags('', $result['content'], true, true, '[[', ']]', [], $maxIterations);
                            }
                            
                            @session_write_close();
                            header('Content-Type: application/json');
                            echo json_encode($result);
                            
                            $(document).on('click', '.read-more', function(e) {
                              e.preventDefault();
                              var id = $(this).data('id') || 0;
                            
                              $.ajax({
                                url: "/assets/ajax.php",
                                type: "GET",
                                data: { action: "getContent", id: id },
                                dataType: "json",
                                success: function(response) {
                                  if (response.content) {
                                    $("#content").html(response.content);
                                    $("#orderModalLabel").text(response.pagetitle);
                                    $("#mymodal").modal('show');
                                  }
                                },
                                error: function(xhr, status, error) {
                                  console.error("An error occurred: " + error);
                                }
                              });
                            });

                            <div class="modal fade" id="mymodal"  tabindex="-1" aria-labelledby="subscribeModalLabel" aria-hidden="true">
                              <div class="modal-dialog modal-xl">
                                <div class="modal-content">
                                  <div class="modal-header">
                                   <h5 class="modal-title" id="orderModalLabel"></h5>
                               <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                  </div>
                                  <div id="content" class="modal-body"></div>
                                  <div class="modal-footer">
                                 <button type="button" class="fs-5 btn btn-warning" data-bs-dismiss="modal">Закрыть</button>
                                  </div>
                                </div>
                              </div>
                            </div>
                    2. Ян 05 декабря 2018 # 0
                      а как осуществить подгрузку из MIGX?

                      Написал опросник:
                      Вопросы созданы при помощи MIGX на странице id=15 таблица Quests
                      На странице «вопрос-ответ» ajaxform проверяет правильность ответа на вопрос №1 и в случае true записывает hookmyform результаты в таблицу Answers результатов MIGX, после чего должен отобразиться следующий вопрос №2 и соответственно новая форма под новый ответ Без перезагрузки страницы целиком
                      Из вашей статьи понимаю, что нужно использовать отдельный файл php, а вот дальше знаний и логики не хватает

                      Буду очень признателен за помощь. Только осваиваю данную тему

                      1. Сергей Шлоков 05 декабря 2018 # 0
                        Не работал с MIGX. Поэтому помочь вряд ли смогу.
                      2. Петр Синечёв 20 февраля 2019 # 0
                        Здравствуйте, пробую сделать авторизацию в модальном окне.
                        При использовании ajax.php не выводятся лексиконы в окне (и я надеюсь, что именно поэтому так же не появляются всплывающие подсказки jgrowl)

                        Второй непонятный момент
                        скрипт, переключающий табы внутри модального окна тоже перестал работать при использовании ajax.php
                        $( ".reg-link" ).click(function() {
                            $('#myTab li:nth-child(2) a').tab('show');
                            $('#modal-title').text('Регистрация');
                        });
                        1. Николай 26 января 2021 # 0
                          Здравствуйте, всё сделал по инструкции, всё работает. Спасибо.

                          Есть нюанс:p Если в ресурсе было ютуб-видео, то при закрытии всплывающего окна оно продолжит воспроизводиться «неизвестно где». Подскажите, можно что-то прописать, чтобы с закрытием окна прекращалось и воспроизведение видео?
                          1. Николай 26 января 2021 # 0
                            Решилось таким скриптом
                            $('#smallmodal').on('hidden.bs.modal', function (event){
                                let iframes = event.target.getElementsByTagName('iframe');
                                for (let i = 0; i < iframes.length; i++) {
                                    let src_tmp = iframes[i].src;
                                    iframes[i].src = '';
                                    setTimeout(() => {
                                        iframes[i].src = src_tmp;
                                    }, 100);
                                }
                            });

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

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