Ajax
Модуль elgg/Ajax (введён в Elgg 2.1) предоставляет набор методов для общения с сервером кратким и единообразным способом, что позволяет плагинам совместно работать над данными запроса, ответом сервера и возвращаемыми клиентскими данными.
Содержание
Обзор
Все методы ajax выполняют следующее:
На стороне клиента опция
data(если передана как объект) фильтруется хукомajax_request_data.Запрос отправляется на сервер, либо отображая представление или форму, вызывая действие, либо загружая путь.
Метод возвращает объект
jqXHR, который можно использовать как Promise.Контент, эхом возвращённый сервером, преобразуется в объект
Объект фильтруется событием
ajax_results.Объект используется для создания HTTP-ответа.
На стороне клиента данные ответа фильтруются хуком
ajax_response_data.Promise
jqXHRразрешается, и вызываются любые обратные вызовыsuccess.
Дополнительные примечания:
Все хуки имеют тип в зависимости от метода и первого аргумента. См. ниже.
По умолчанию модуль
elgg/spinnerавтоматически используется во время запросов.Пользовательские сообщения, сгенерированные
elgg_register_success_message()иelgg_register_error_message(), собираются и отображаются на клиенте.Elgg предоставляет вам обработчик ошибок по умолчанию, который показывает общее сообщение, если вывод не удался.
Исключения PHP или отказанный ресурс возвращают коды ошибок HTTP, что приводит к использованию клиентского обработчика ошибок.
Метод HTTP по умолчанию —
POSTдля действий, в противном случаеGET. Вы можете установить его черезoptions.method.Если передан непустой
options.data, метод по умолчанию всегдаPOST.Для клиентского кэширования установите
options.methodв"GET"иoptions.data.elgg_response_ttlв желаемый max-age в секундах.Чтобы сохранить системные сообщения для следующей загрузки страницы, установите
options.data.elgg_fetch_messages = 0. Вы можете захотеть сделать это, если намерены перенаправить пользователя на основе ответа.Чтобы остановить требование клиентским API модулей, требуемых на стороне сервера с
elgg_import_esm(), установитеoptions.data.elgg_fetch_deps = 0.Все методы принимают строку запроса в первом аргументе. Это передаётся в URL fetch, но не появляется в типах хуков.
Выполнение действий
Рассмотрим это действие:
// in myplugin/actions/do_math.php
elgg_ajax_gatekeeper();
$arg1 = (int)get_input('arg1');
$arg2 = (int)get_input('arg2');
// will be rendered client-side
elgg_register_success_message('We did it!');
echo json_encode([
'sum' => $arg1 + $arg2,
'product' => $arg1 * $arg2,
]);
Для его выполнения используйте ajax.action('<action_name>', options):
var Ajax = require('elgg/Ajax');
var ajax = new Ajax();
ajax.action('do_math', {
data: {
arg1: 1,
arg2: 2
},
}).done(function (output, statusText, jqXHR) {
alert(output.sum);
alert(output.product);
});
Примечания для действий:
- Все хуки имеют тип
action:<action_name>. Таким образом, в этом случае будут запущены три хука: клиентский
"ajax_request_data", "action:do_math"для фильтрации данных запроса (перед отправкой)серверный
"ajax_results", "action:do_math"для фильтрации ответа (после выполнения действия)клиентский
"ajax_response_data", "action:do_math"для фильтрации данных ответа (перед получением вызывающим кодом)
- Все хуки имеют тип
Токены CSRF добавляются в данные запроса.
Метод по умолчанию —
POST.Абсолютный URL действия может быть указан вместо имени действия.
Примечание
При установке data используйте ajax.objectify($form) вместо $form.serialize(). Это позволяет сработать хуку плагина ajax_request_data и другим плагинам изменять/присоединяться к запросу.
Получение данных
Рассмотрим этот PHP-скрипт, который работает по адресу http://example.org/myplugin_time.
// in myplugin/elgg-plugin.php
return [
'routes' => [
'default:myplugin:time' => [
'path' => '/myplugin_time',
'resource' => 'myplugin/time',
],
],
];
// in myplugin/views/default/resources/myplugin/time.php
elgg_ajax_gatekeeper();
echo json_encode([
'rfc2822' => date(DATE_RFC2822),
'day' => date('l'),
]);
return true;
Для получения его вывода используйте ajax.path('<url_path>', options).
var Ajax = require('elgg/Ajax');
var ajax = new Ajax();
ajax.path('myplugin_time').done(function (output, statusText, jqXHR) {
alert(output.rfc2822);
alert(output.day);
});
Примечания для путей:
3 хука (см. Действия выше) будут иметь тип
path:<url_path>. В данном случае «path:myplugin_time».Если обработчик страницы эхом возвращает обычную веб-страницу,
outputбудет строкой, содержащей HTML.Абсолютный URL может быть указан вместо имени пути.
Получение представлений
Рассмотрим это представление:
// in myplugin/views/default/myplugin/get_link.php
if (empty($vars['entity']) || !$vars['entity'] instanceof ElggObject) {
return;
}
$object = $vars['entity'];
/* @var ElggObject $object */
echo elgg_view('output/url', [
'text' => $object->getDisplayName(),
'href' => $object->getUrl(),
'is_trusted' => true,
]);
Поскольку это файл PHP, мы должны сначала зарегистрировать его для Ajax:
// in myplugin_init()
elgg_register_ajax_view('myplugin/get_link');
Для получения представления используйте ajax.view('<view_name>', options):
var Ajax = require('elgg/Ajax');
var ajax = new Ajax();
ajax.view('myplugin/get_link', {
data: {
guid: 123 // querystring
},
}).done(function (output, statusText, jqXHR) {
$('.myplugin-link').html(output);
});
Примечания для представлений:
3 хука (см. Действия выше) будут иметь тип
view:<view_name>. В данном случае «view:myplugin/get_link».outputбудет строкой с отрисованным представлением.Данные запроса внедряются в
$varsв представлении.Если данные запроса содержат
guid, система устанавливает$vars['entity']в соответствующую сущность илиfalse, если её нельзя загрузить.
Предупреждение
В представлениях и формах ajax обратите внимание, что $vars может быть заполнено клиентским вводом. Данные фильтруются как get_input(), но могут быть не того типа, который вы ожидаете, или иметь неожиданные ключи.
Получение форм
Предположим, у нас есть представление формы. Мы регистрируем его для Ajax:
// in myplugin_init()
elgg_register_ajax_view('forms/myplugin/add');
Для получения этого используйте ajax.form('<action_name>', options).
var Ajax = require('elgg/Ajax');
var ajax = new Ajax();
ajax.form('myplugin/add').done(function (output, statusText, jqXHR) {
$('.myplugin-form-container').html(output);
});
Примечания для форм:
3 хука (см. Действия выше) будут иметь тип
form:<action_name>. В данном случае «form:myplugin/add».outputбудет строкой с отрисованным представлением.Данные запроса внедряются в
$varsв вашем представлении формы.Если данные запроса содержат
guid, система устанавливает$vars['entity']в соответствующую сущность илиfalse, если её нельзя загрузить.
Примечание
Только данные запроса передаются в запрашиваемое представление формы (т.е. как третий параметр, принимаемый elgg_view_form()). Если вам нужно передать атрибуты или параметры элемента формы, отображаемого представлением input/form (т.е. обычно передаваемые как второй параметр в elgg_view_form()), используйте серверное событие view_vars, input/form.
Предупреждение
В представлениях и формах ajax обратите внимание, что $vars может быть заполнено клиентским вводом. Данные фильтруются как get_input(), но могут быть не того типа, который вы ожидаете, или иметь неожиданные ключи.
Отправка форм
Для отправки формы с помощью Ajax просто передайте параметр ajax с переменными формы:
echo elgg_view_form('login', ['ajax' => true]);
Перенаправления
Используйте ajax.forward() для запуска спиннера и перенаправления пользователя на новое назначение.
var Ajax = require('elgg/Ajax');
var ajax = new Ajax();
ajax.forward('/activity');
Присоединение к запросу Ajax
Клиентский хук ajax_request_data можно использовать для добавления или фильтрации данных, отправляемых запросом elgg/Ajax.
Допустим, когда получается представление foo, мы хотим также отправить серверу некоторые данные:
// in your boot module
var Ajax = require('elgg/Ajax');
var hooks = require('elgg/hooks');
var ajax = new Ajax();
hooks.register(Ajax.REQUEST_DATA_HOOK, 'view:foo', function (name, type, params, data) {
// send some data back
data.bar = 1;
return data;
});
Эти данные можно прочитать на стороне сервера через get_input('bar');.
Примечание
Если данные были переданы как строка (например, $form.serialize()), хуки запроса не запускаются.
Примечание
Форма будет объективирована как FormData, и тип содержимого запроса будет определён соответствующим образом.
Присоединение к ответу Ajax
Серверное событие ajax_results можно использовать для добавления или фильтрации данных ответа (или метаданных).
Допустим, когда получается представление foo, мы хотим также отправить клиенту дополнительные данные:
function myplugin_append_ajax(\Elgg\Event $event) {
/* @var $data /stdClass */
$data = $event->getValue();
// alter the value being returned
$data->value .= " hello";
// send some metadata back
$data->myplugin_alert = 'Listen to me!';
return $data;
}
// in myplugin_init()
elgg_register_event_handler('ajax_results', 'view:foo', 'myplugin_append_ajax');
Для захвата метаданных, отправляемых обратно клиенту, мы используем клиентский хук ajax_response_data:
// in your boot module
var Ajax = require('elgg/Ajax');
var hooks = require('elgg/hooks');
hooks.register(Ajax.RESPONSE_DATA_HOOK, 'view:foo', function (name, type, params, data) {
// the return value is data.value
// the rest is metadata
alert(data.myplugin_alert);
return data;
});
Примечание
Только data.value возвращается в функцию success или доступно через интерфейс Deferred.
Примечание
Elgg использует те же хуки для доставки системных сообщений через ответы elgg/Ajax.
Обработка ошибок
Ответы в основном делятся на три категории:
Успех HTTP (200) со статусом
0. На сервере не было вызововelgg_register_error_message().Успех HTTP (200) со статусом
-1. Был вызванelgg_register_error_message().Ошибка HTTP (4xx/5xx). Например, вызов действия с устаревшими токенами или исключение сервера. В этом случае обратные вызовы
doneне вызываются.
Первый и третий случаи являются наиболее распространёнными в системе. Используйте обратные вызовы done и fail для дифференциации поведения при успехе и ошибке.
ajax.action('entity/delete?guid=123').done(function (value, statusText, jqXHR) {
// remove element from the page
}).fail(function() {
// handle error condition if needed
});
Требование модулей ES
Каждый ответ от сервиса Ajax будет содержать список модулей ES, требуемых на стороне сервера с elgg_import_esm(). Когда данные ответа распаковываются, эти модули будут загружены асинхронно — плагины не должны ожидать, что эти модули будут загружены в их обработчиках $.done() и $.then(), и должны использовать import для любых модулей, от которых они зависят. Кроме того, модули не должны ожидать, что DOM был изменён запросом Ajax при их загрузке — события DOM должны быть делегированы, а манипуляции с элементами DOM должны быть отложены до разрешения всех запросов Ajax.