Ajax (Asynchronous Javascript and XML — «асинхронный JavaScript и XML») - это процесс динамического обновления частей HTML-страницы на основе данных с сервера. Со стороны клиента (веб-браузера) выполняется запрос на сервер с помощью XMLHttpRequest, сервер в свою очередь выполняет необходимые действия и возвращает ответ в виде заголовков и данных в формате JSON или XML (так же можно передвать другие типы данных, к примеру HTML или текст, но указанные 2 формата наиболее популярны), далее скрипт, который инициализировал запрос распоряжается полученными данными по предварительно заданному алгоритму.
Но наша цель не изучение самой технологии AJAX, а его практическое применение в CMS Drupal 9/10/11 (далее Drupal). В связи с этим рекомендуется перед началом изучения статьи, ознакомиться c AJAX подходом.
В "ядре" Drupal реализован инструментарий для работы с наиболее часто встречающимися AJAX командами а так же предусмотрена возможность создания своих команд, для решения конкретной задачи. Общий алгоритм взаимодействия следующий:
- Создается гиперссылка с классом "use-ajax"
- По клику на ссылку с указанным классом, скрипт (core/misc/ajax.js) выполняет асинхронный запрос на сервер, по указанному в аттрибуте HREF гиперссылки пути.
- На стороне сервера, по пути, на которую ссылается гиперссылка, вызывается контролер, который выполняет все необходимые действия, генерирует список команд и возвращает формате JSON.
- Скрипт получает набор команд и поочередно выполняет их.
А теперь подробнее разберем выше описанный процесс на примере отображения сообщения по клику на ссылку.
Часть 1: Создание гиперссылок и автоматическая отправка запроса.
Гиперссылки вы можете создать любым удобным способом (добавив ссылки из текстового редактора, описав в файле шаблона TWIG или создав программный блок с текстом...). Важны 2 фактора:
- наличи аттрибута href, где указан URL, который должен обработать AJAX запрос;
- класс use-ajax, который является "индикатором" того, что клик по данной ссылке должен быть обработан скриптом.
Для корректной обработки AJAX ссылок, необходимо, чтобы на странице, где выводится данная ссылка, была подключена библиотека core/drupal.ajax (core/misc/ajax.js). Для решения этой задачи есть несколько способов.
- Основной способ подключения, если на целевой странице вы используете подключения js/css, то указываем зависимость
dependencies:
  - core/drupal.ajax
- Если ссылка выводится с помощью программного кода, то можно в "render массиве" указать следующее:
$output['#attached']['library'][] = 'core/drupal.ajax';
- Если ссылка выводится в TWIG шаблоне, то можно использовать следующую конструкцию
{{ attach_library('core/drupal.ajax') }}
- Есть более универсиальный вариант, подключить библиотеку в хуке hook_page_alter (файл mymodule.module):
function mymodule_page_alter(&$page) {
  if(***ATTACH CONDITIONS***){
    $page['#attached']['library'][] = 'core/drupal.ajax';
  }
}
Где ***ATTACH CONDITIONS*** - условия, по которой определяете когда необходимо подключать AJAX библиотеку.
Или любым другим известным вам вариантом подключения библиотеки к странице.
После подключения библиотеки, все ссылки с классом use-ajax будут выполнять асинхронные(AJAX) запросы.
Часть 2: Обработка запроса.
Как уже было ранее сказано, после того, как произошло событие клика на ссылку, выполняется запрос по URL, который указан в аттрибуте href. Для обработки запроса нам нужно создать контроллер, который будет вызываться по обращению на указанный URL.
Для начала "расскажем" Drupal-у о том, что по указанной ссылке. Создаем модуль: для примера допустим, что наш модуль называется cusom_ajax, контролер обработчика будет доступен по адресу /ajax/show-message.
Создаем папку custom_ajax в modules/custom/. Добавляем файл опсиания custom_ajax.info.yml
name: Custom ajax
description: 'My first module'
type: module
core_version_requirement: ^9.1 || ^10 || ^11
Теперь описываем новую страницу с помощью файла custom_ajax.routing.yml
custom_ajax.ajax:
  path: '/ajax/show-message'
  defaults:
    _controller: '\Drupal\cusom_ajax\Controller\CustomAjaxController::ajax_show_message'
  requirements:
    _permission: 'access content'
Этим файлом "указали" Drupal-у следующую инструкцию: при обращении по пути /ajax/show-message необходимо вывзвать метод ajax_show_message который находится в классе CustomAjaxController. А так же указали путь, где находится указанный класс (в нашем случае это /modules/custom/custom_ajax/src/Controller/CustomAjaxController.php).
// Определяем область видимости нашего класса.
namespace Drupal\cusom_ajax\Controller;
// Импортируем зависимости.
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AlertCommand;
/**
 * Определяем контролер CustomAjaxController.
 */
class CustomAjaxController extends ControllerBase {
  public function ajax_show_message() {
    // Создаем экземпляр класса AjaxResponse().
    $response = new AjaxResponse();
    // Добавляем команду js: alert().
    $response->addCommand(new AlertCommand('Hello world'));
    //Возвращаем набор команд для выполнения.
    return $response;
  }
}
Включаем модуль, выполняем клик на ссылку и получаем alert окно с текстом Hello World.
В примере мы использовали только команду AlertCommand(). В ядре Drupal-а есть набор предустановленных команд. вот некоторые из них:
- AlertCommand - вызывает alert();
- RedirectCommand - выполняет ajax перенаправление;
- AddCssCommand - добавляет css на страницу;
- InvokeCommand - выполняет пользовательскую команду jQuery;
- CssCommand - выполняет команду jQuery.css();
- AfterCommand - выполняет команду jQuery.after();
- BeforeCommand - выполняет команду jQuery.before();
- AppendCommand - выполняет команду jQuery.append();
- PrependCommand - выполняет команду jQuery.prepend();
- ChangedCommand - отмечает элемент классом "ajax-changed";
- HtmlCommand - выполняет команду jQuery.html();
- DataCommand - выполняет команду jQuery.data();
- InsertCommand - выполняет команду jQuery.insert();
- RemoveCommand - выполняет команду jQuery.remove();
- ReplaceCommand - выполняет команду jQuery.replaceWith().
Полный список команд можно посмотреть тут
Часть 3: Создаем свои команды.
Встроенные команды дают широкие возможности, но иногда бывает необходимо выполнить определенный набор действий отличающихся от предустановленных. Попытка решить задачу реализовав ее встроенными командами чаще всего приводит к нечитаемому и не расширяемому коду или вообще оказывается невозможной... Для подобных случаев предусмотрена возможность создания своих комманд.
Для примера создадим команду прокрутки до определенного элемента на странице со сдвигом на указанное кол-во px.
Для начала опишем нашу команду. Создаем файл src/Ajax/ScrollToCommand.php и опишем класс ScrollToCommand.
<?php
// Определяем область видимости.
namespace Drupal\cusom_ajax\Ajax;
// Импортируем зависимости.
use Drupal\Core\Ajax\CommandInterface;
class ScrollToCommand implements CommandInterface {
  // Описываем необходимые переменные.
  protected $selector;
  protected $offset;
  protected $speed;
  // Присваивем переменным значение при создании объекта класса.
  public function __construct($selector, $offset = 0, $speed = 500) {
    $this->selector = $selector;
    $this->offset = $offset;
    $this->speed = $speed;
  }
  /**
   * Выполняем Drupal\Core\Ajax\CommandInterface:render().
   */
  public function render() {
    return array(
      'command' => 'scrollTo',
      'selector' => $this->selector,
      'offset' => $this->offset,
      'speed' => $this->speed,
    );
  }
}
Теперь создадим файл с реализацией комманды и разместим его в папке js в корне нашего модуля. Добавим новый метод в Drupal.AjaxCommands.
(function ($, Drupal) {
  /**
   * Добавим новыую команду scrollTo.
   */
  Drupal.AjaxCommands.prototype.scrollTo = function (ajax, response, status) {
    // Проверяем наличие селектора в переданных данных.
    if (!response.selector) {
      return;
    }
    // Находим необходимый элемент и проверяем существует элемент на странице или нет.
    var $wrapper = $(response.selector);
    if(!$wrapper.length){
      return;
    }
    // Высчитываем положение элемента и необходимый сдвиг.
    var top = $wrapper.offset().top;
    var offset = response.offset ? response.offset : 0;
    // Получаем скорость скорллинга.
    var speed = responce.spped ? responce.spped : 500;
    // Прокручиваем страницу до высчитанной точки.
    $('html,body').stop().animate({
      scrollTop: top + offset
    }, speed);
  }
})(jQuery, Drupal);
В параметре response мы получаем все переданные из Drupal\craft\Ajax\ScrollToCommand::render() значения и выполняем необходимый набор действий.
Осталось дело за малым: в нашем контролере импортируем класс с описанной командой и вызываем его.
// Определяем область видимости нашего класса.
namespace Drupal\cusom_ajax\Controller;
// Указываем зависимости.
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\cusom_ajax\Ajax\ScrollToCommand;
/**
 * Определяем контролер CustomAjaxController.
 */
class CustomAjaxController extends ControllerBase {
  public function ajax_show_message() {
    // Создаем экземпляр класса AjaxResponse().
    $response = new AjaxResponse();
    // Добавляем нашу команду scrollTo со сдвигом -90px.
    $response->addCommand(new ScrollToCommand('#custom-block-selector', -90));
    //Возвращаем набор команд для выполнения.
    return $response;
  }
}
На этом все. Теперь вы можете создавать свои команды. Но всегда помните, если ваша задача решается парой предустановленных комманд, то писать свою команду нет смысла.
 
Добавить комментарий