Ajax-запросы нативными средствами Joomla
Небольшая заметка о том, как делать ajax-запросы штатными средствами без использования дополнительных js-библиотек (jQuery, etc). Joomla 3 и Joomla 4 предоставляют небольшую обёртку для конструирования XMLHttpRequest. В целом синтаксис очень похож на тот же jQuery Ajax, поэтому заменить его будет очень легко.
В <head> страницы можно увидеть core.js, в котором есть немало любопытных функций для работы с фронтом на Joomla. Об одной из них (получение данных из php в js) писалось здесь: Разработка форм обратной связи для магазинов на Joomla 3. Для создания ajax-запросов нам пригодится Joomla.request.
Ajax в Joomla - Joomla.request
Joomla 3
Представим, что Вам нужно просто отправить запрос, не получая никаких данных:
Joomla.request({ url: 'index.php?option=com_example&view=example' })
Выбор метода запроса (POST или GET)
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST' })
Если выбран метод запроса POST. то автоматически будет отправляться заголовок X-CSRF-Token и сам CSRF-токен, который можно и нужно проверить в точке входа.
Проверка CSRF-токена в точке входа
Для этого используем метод Session::checkToken. В качестве параметра можно указывать как post (это значение по умолчанию), так и get.
use Joomla\CMS\Session\Session; use Joomla\CMS\Language\Text; Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
Проверить наличие CSRF-токена на странице можно в консоли браузера:
Если CSRF-токена в Joomla Script options нет, то в PHP можно его добавить с помощью класса HTMLHelper.
HTMLHelper::_('form.csrf');
Установка заголовков ajax-запроса
Есть возможность установки своих заголовков ajax-запроса. Например, заголовка Cache-Control, тогда будет корректно работать условная ajax-корзина, каждый раз получая свежие данные. Также можно устанавливать свои уникальные заголовки, если это необходимо.
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST', headers: { 'Cache-Control' : 'no-cache', 'Your-custom-header' : 'custom-header-value' } })
Отправка данных через ajax в Joomla
Отправка данных на выбранный url происходит согласно спецификации. Чаще всего это или строка или объект. Для того, чтобы данные пришли в удобном виде стоит применить к передаваемому объекту JSON.stringify, так же указать заголовок запроса Content-type:applictation/json. Хорошая статья о FormData на learn.javascript.ru в помощь.
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST', headers: { 'Cache-Control' : 'no-cache', 'Your-custom-header' : 'custom-header-value', 'Content-Type': 'application/json' }, data: JSON.stringify({ 'key1' : 'value1', 'key2' : 'value2' }) })
Если метод запроса POST, в data передается просто строка и не установлен заголовок Content-Type, то он (Content-Type) принимает значение application/x-www-form-urlencoded. В php получаем данные следующим образом:
use Joomla\CMS\Factory; $data = Factory::getApplication()->input->json->getArray();
Callback-функции ajax-запроса в Joomla
-
onBefore: function(xhr){} - выполняется перед запросом. Запрос не выполнится, если данный callback вернёт false.
-
onSuccess: function(response, xhr){} - выполняется после успешного завершения запроса. response - это xhr.responseText,
-
onError: function(xhr){} - выполняется после неудачного запроса.
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST', headers: { 'Cache-Control' : 'no-cache', 'Your-custom-header' : 'custom-header-value', 'Content-Type': 'application/json' }, data: JSON.stringify({ 'key1' : 'value1', 'key2' : 'value2' }), onBefore: function (xhr){ // Тут делаем что-то до отправки запроса. // Если вернём false - запрос не выполнится }, onSuccess: function (response, xhr){ // Тут делаем что-то с результатами //Проверяем пришли ли ответы if (response !== ''){ let jshopping_cart = JSON.parse(response); // И дальше делаем, например, супер-аякс-корзину-под-joomshopping } }, onError: function(xhr){ // Тут делаем что-то в случае ошибки запроса. // Получаем коды ошибок и выводим сообщения о том, что всё грустно. } })
Запрос обёрнут в try-catch, поэтому если запрос не проходит - смотрим в консоль, там должна логироваться ошибка.
Флаг perform
Это значение по умолчанию установлено в true. Если установить в false - запрос не будет выполняться, а так же не будет вызываться callback-функция onBefore. Полезно в тех случаях, когда не нужно в процессе разработки некоторое время дёргать лишний раз сервер.
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST', headers: { 'Cache-Control' : 'no-cache', 'Your-custom-header' : 'custom-header-value', 'Content-Type': 'application/json' }, data: JSON.stringify({ 'key1' : 'value1', 'key2' : 'value2' }), onBefore: function (xhr){ // Тут делаем что-то до отправки запроса. // Если вернём false - запрос не выполнится }, onSuccess: function (response, xhr){ // Тут делаем что-то с результатами //Проверяем пришли ли ответы if (response !== ''){ let jshopping_cart = JSON.parse(response); // И дальше делаем, например, супер-аякс-корзину-под-joomshopping } }, onError: function(xhr){ // Тут делаем что-то в случае ошибки запроса. // Получаем коды ошибок и выводим сообщения о том, что всё грустно. }, perform : false // вся проделанная выше работа бесполезна. Запрос прерван. })
Joomla 4
В Joomla 4 метод переписан, но для простых смертных всё остается так же. Добавляется лишь ещё одна callback-функция onComplete, которая выполняется в любом случае - как после успешного запроса, так и в случае ошибки.
Joomla.request({ url: 'index.php?option=com_example&view=example', method: 'POST', headers: { 'Cache-Control' : 'no-cache', 'Your-custom-header' : 'custom-header-value', 'Content-Type': 'application/json' }, data: JSON.stringify({ 'key1' : 'value1', 'key2' : 'value2' }), onBefore: function (xhr){ // Тут делаем что-то до отправки запроса. // Если вернём false - запрос не выполнится }, onSuccess: function (response, xhr){ // Тут делаем что-то с результатами //Проверяем пришли ли ответы if (response !== ''){ let jshopping_cart = JSON.parse(response); // И дальше делаем, например, супер-аякс-корзину-под-joomshopping } }, onError: function(xhr){ // Тут делаем что-то в случае ошибки запроса. // Получаем коды ошибок и выводим сообщения о том, что всё грустно. }, onComplete: function (xhr){ // Тут что-то делаем в любом случае после ajax-запроса. // в не зависимости от результата. } });
Новое в Joomla 4.2
В Joomla 4.2 добавили флаг promise
, чтобы вызывать Promise
:
Joomla.request = (options) => { // Подготовьте варианты const newOptions = Joomla.extend({ url: '', method: 'GET', data: null, perform: true, promise: false, }, options); // Вернуть обещание if (newOptions.promise) { return new Promise((resolve, reject) => { newOptions.perform = true; createRequest(resolve, reject); }); }
Также добавили очередь (FIFO queue of requests to execute serially) в виде Joomla.enqueueRequest
.
Joomla.enqueueRequest({ url: options.ajaxUrl, method: 'GET', promise: true }).then(xhr => { const response = xhr.responseText; const updateInfoList = JSON.parse(response); if (Array.isArray(updateInfoList)) { if (updateInfoList.length === 0) { // No updates update('success', Joomla.Text._('PLG_QUICKICON_EXTENSIONUPDATE_UPTODATE')); } else { update('danger', Joomla.Text._('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND').replace('%s', `<span class="badge text-dark bg-light">${updateInfoList.length}</span>`)); } } else { // An error occurred update('danger', Joomla.Text._('PLG_QUICKICON_EXTENSIONUPDATE_ERROR')); } }).catch(() => { // An error occurred update('danger', Joomla.Text._('PLG_QUICKICON_EXTENSIONUPDATE_ERROR')); });
Оригинал: https://habr.com/ru/articles/588651/