Небольшая заметка о том, как делать 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 происходит согласно спецификации. Чаще всего это или строка или объект.
Joomla.request({
url: 'index.php?option=com_example&view=example',
method: 'POST',
headers: {
'Cache-Control' : 'no-cache',
'Your-custom-header' : 'custom-header-value'
},
data: {
'key1' : 'value1',
'key2' : 'value2'
}
})
Если метод запроса POST, в data передается просто строка и не установлен заголовок Content-Type, то он (Content-Type) принимает значение application/x-www-form-urlencoded.
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'
},
data: {
'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'
},
data: {
'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'
},
data: {
'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-запроса.
// в не зависимости от результата.
}
});
Приветствую аргументированные замечания и пожелания к заметке.
Комментарии (12)
SergeiMinaev
11.11.2021 18:37+1Joomla 3 и Joomla 4 предоставляют небольшую обёртку для конструирования XMLHttpRequest
В чём смысл использовать XMLHttpRequest, когда более современный fetch не поддерживается только в IE?
sergeytolkachyov Автор
11.11.2021 18:46Я про fetch не знал, хотя возможно, что он давно уже существует. В своей работе сталкиваюсь в основном с бэком. Насколько велика разница между XMLHttpRequest и fetch кроме синтаксиса?
SergeiMinaev
11.11.2021 20:28Существует давно, года с 2015-го. Принципиальной разницы нет. Насколько я знаю, основная фишка fetch - он возвращает промисы, которые, соответственно, можно чейнить. За счёт этого определённые штуки получаются компактнее.
sergeytolkachyov Автор
11.11.2021 20:32Фронтовые нюансы, в общем и целом) Это писалось больше для тех, кто подключает jquery, а порой и не один экземпляр ради того, что уже реализовано в ядре CMS.
zkrvndm
16.11.2021 19:34Поддерживаются ли промисы? Например, тот же jQuery.ajax() умеет в промисы, достаточно добавить await, чтобы убедиться, а здесь с этим как?
sergeytolkachyov Автор
16.11.2021 20:48Почитал про промисы - такого, чтоб цепочки делать нет. В тройке точно, в четвёрке надо посмотреть, но вроде тоже нет. Только описанные колбэки.
zkrvndm
17.11.2021 05:22Промисы это не про цепочки, промисы это про удобство. Нет смысла использовать Joomla .request() когда из под корокби в Joomla 3 идет библиотка jQuery, при этом она уже подключена, делать ничего не надо. И самое главное ее достоинство, что с ней можно использовать await! Просто оцените насколько удобнее делать запросы:
response = await jQuery.ajax({ url: '/', method: 'POST', headers: { 'x-csrf-token': Joomla.getOptions('csrf.token') }, data: { key1: 'value1', key2: 'value2' } }); console.log("Ответ сервера:\n" + response);
Не нужно никаких колбеков для ожидания ответа, нет лишних вложенностей, можно просто дальше работать с ответом, словно пишешь синхронный код. Токен конечно сам не добавляется, но ни что не мешает указать его в заголовках самому.
mobi
16.11.2021 23:14Нативно — нет (скорее всего из-за обратной совместимости). Но если очень хочется, то никто не запрещает обернуть самостоятельно, скорее всего должно получиться как-то так:
const jRequest = url => new Promise((resolve, reject) => { Joomla.request({ url: url, onSuccess: (_, response) => resolve(response), onError: reject, }); });
sergeytolkachyov Автор
17.11.2021 07:22Я пытаюсь представить задачи, в рамках которых может потребоваться await на сайте. В joomla ajax-запросы делаются для получения данных из модуля, плагина или (реже) компонента на том же сайте. Физически запрос идёт на тот же сервер и если он отдал вёрстку, то и ответ на запрос вряд заставит себя долго ждать. В Joomla 4 есть rest API из коробки, но вряд ли фронт будут писать на joomla.request. Запросы к удалённому серверу, от ответа которого зависят данные на странице - согласен. Но мне кажется, что joomla.request больше для внутреннего пользования. Представить сайт, где внешних запросов нет, анимации в дизайне сделаны на css. Тогда jquery не слишком нужен. И сеошник будет спокойнее, зная, что не грузится ещё одна неиспользуемая библиотека от 60 до 200кб весом.
Akuma
Fetch?
mobi
У
Joomla.request
есть одно преимущество передfetch
: для POST-запросов автоматически добавляется CSRF-токен (если он, конечно, на странице задан вызовомHTMLHelper::_('form.csrf')
).