Функциональный модуль AjDir связывает серверный backend и браузерный frontend.
Он позволяет загружать компоненты xTables и другое содержимое на страницу через ajax запросы в ajax контейнерах.
Каждый ajax контейнер имеет свое вероятностное уникальное имя и связан с одним или несколькими селекторами страницы. Он может загружать за раз как один, так и множество компонентов и содержимого, автоматически обновлять данные через заданный промежуток времени при необходимости.
Также он позволяет загружать данные с других доменов в режиме кросс-доменных ajax запросов.
При загрузке ajax dispatcher осуществляется его связка с селекторами, которые он обслуживает. В последующем возможен вызов ajax dispatcher, например, для его перезагрузки или подгрузки в селектор другого содержимого, через название селектора. Если в том же селекторе регистрируется другой ajax dispatcher, то старый удаляется.
Модуль AjDi состоит из класса xtables\base\AjDi
и js функий, располагаемых в
файле xtables.js
.
JS функции, обслуживающие ajDi, могут получать данные локально из функций, для чего вместо href
и
data-url
, нужно использовать параметр target
(подробнее)
и data-target
(подробнее).
На сервере могут быть использованы следующие методы:
Помещает js код с вызовом ajax dispatcher в нужном метсе страницы. В метод нужно передать массив именованных параметров:
url
- обязательно
роут, по которому со страницы будет сделан запрос через ajax для загрузки содержимого;;
data
- необязательно
ассоциативный массив с параметрами, которые должны быть переданы в аякс запросе;
refresh
- необязательно
время в секундах для обновления содержимого аякс контейнера;
reload_bundles
- необязательно
простой массив с именами селекторов (['#some', '#some2']
)
или строка с именами селекторов через запятую;
history
- необязательно
адрес для добавления история для аякс навигации.
use xtables\base\AjDi;
AjDi::getStart([
'url' => '/incoming/ajax-data',
'data' => [
'some' => 'val',
'some1' => 'val2'
],
'refresh' => 300,
'reload_bundles' => ['#some-selector', '#else-selector'],
'history' => '/some/new/url'
]);
Упрощенный (более старый) метод. Помещает js код с вызовом ajax dispatcher в нужном месте страницы. В данный метод передаются:
$url
- обязательно роут, по которому со страницы будет
сделан запрос через ajax для загрузки содержимого;
$params
- необязательно могут быть переданы параметры
в массиве, тогда они будут переданы на страницу загрузки, указанную в url (по умолчанию пустой массив);
$updateTimeSec
- необязательно может быть указано количество
секунд, по истечение которых ajDi
должен обновлять содержимое (по умолчанию стоит
значение ноль и перезагрузка не осуществляется);
ajDi
при обращении к url сообщит свое имя во входном параметре 'ajax_dispatcher'
,
оно соответствует значению xtables.AJDI
.
use xtables\base\AjDi;
AjDi::getJs('/incoming/ajax-data', $this->params, 300);
После помещения js кода нужно создать роут с методом, который будет соответствовать url и будет отдавать содержимое по запросу
от ajDi
.
В методе модели, к которой будет обращаться метод контроллера, нужно вызвать метод
xtables\base\AjDi::getReply($reply)
, в который должен быть передан ассоциативный массив.
Метод возвратит отформатированный для отправки ответ.
Передаваемый в метод массив $reply
должен состоять из:
ключей, соответствующих элементам DOM, в которые должно быть загружено содержимое; элементы должны именоваться по
правилам css: класс как '.some-class'
, идентификатов как '#some-id'
в качестве значений нужно добавить содержимое, в том числе html,
которое будет вставлено в элемент DOM, соответствующий наименованию ключа массива
ajDi
может вставить содержимое не ограничивается. Если
включено автообновление, то ajDi
будет обновлять их все. Если нужно раздельное обновление, то
нужно вызвать несколько ajDi
.
'#some-id' => 'some value',
'#else-id' => '<p>else value</p>'
Если необходимо добавить элемент в верхний инфоблок (по умолчанию расположен вверху справа в системном
лейауте xtables-basic
, который будет скрываться после перезагрузки через аякс диспетчеры,
то необходимо передать второй параметр:
content
- обязательно
содержимое элемента инфоблока;
limit
- необязательно
если данный параметр не определен, то действие элемента инфоблока будет
распространяться только на текущий url;any
,
то элемент инфоблока не будет скрыт после изменения url и будет оставаться,
пока не будет полностью перезагружена страница;
name
- необязательно
по умолчанию, если не передать имя в качестве параметра, то для идентификации
элемента инфоблока будет использоваться имя ajDi, которое определяется динамически
и может изменяться; для фиксации имени инфоблока можно определить данный параметр
с любым подходящим именем, это имя будет добавлено в css id элемента,
соответственно имя не должно содержать пробелов.
Содержимое инфоблока, чтобы корректно отображаться в общей ленте, должно быть сформировано по следующему примеру:
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<!-- some icon or other content -->
</a>
<ul class="dropdown-menu dropdown-menu-right" style="width: 300px; max-height: 300px; overflow-y: auto">
<li style="width: 100%">
<!-- dropdown item -->
</li>
</ul>
AjDi::INFOBLOCK => [
'limit' => 'any',
'name' => 'some-name',
'content' => 'content'
]
Если для обработки ответа ajDi
нужен дополнительный js и/или css файлы, то они могут быть подгружены.
Для этого нужно определить параметр AjDi::IMPORT
с массивом файлов:
/config/js-css-meta.php
,
как они обозначаются при подключении через View
(это удобнее тем, что при изменении местоположения файла, потребуется изменить
его путь только в настроечном файле); если обозначения js и css файлов совпадают, то
будут подгружены оба файла, например: 'date_picker'
, будут подгружены js файл и css файл данного плагина;
AjDi::IMPORT => [
'flot',
'flot_pie',
'date_picker'
]
AjDi::IMPORT => [
'/js/flot/jquery.flot.min.js',
'/js/flot/jquery.flot.pie.min.js',
'/css/jquery.datetimepicker.css',
'/js/jquery.datetimepicker.full.min.js'
]
return AjDi::getReply(
[
'#some' => 'some content',
AjDi::INFOBLOCK => [
'limit' => 'any',
'name' => 'some-name',
'content' => 'infoblock content inc a tag and ul'
],
AjDi::IMPORT => [
'flot',
'flot_pie'
]
]
);
return AjDi::getReply(
[
'#some' => 'some content',
AjDi::INFOBLOCK => [
[
'limit' => 'any',
'content' => 'infoblock content inc a tag and ul'
],
[
'content' => 'infoblock content inc a tag and ul'
]
]
]
);
return AjDi::getReply([
'#some' => 'some content',
AjDi::INFOBLOCK => 'infoblock content inc a tag and ul'
]);
Например, создание диспетчера:
Инициализируем View
. См. View.
Передаем в параметр 'content'
макета View::BASIC_LAYOUT
параметр View::WORKFLOW
(соответствует основной части страницы, где может располагаться большая таблица) с ajDi
,
который будет обращаться по url http://domain/incoming/ajax-data и передаст туда параметры.
use xtables\base\View;
use xtables\base\AjDi;
private function layoutForTableView() {
$view = new View([
'head' => [
'css' => [
'date_picker'
],
'js' => [
'date_picker',
'autocomplete'
]
],
'meta' => [
'title' => 'Журнал',
'description' => 'some description'
],
'layout_name' => 'xtables-basic'
]);
return $view->setContent([
View::PAGE_TITLE => 'Журнал',
View::WORKFLOW => AjDi::getJs('/incoming/ajax-data', $this->params, 300)
])->get();
}
Создание ответа для ajDi
в модели, которая будет вызвана методом контроллера:
use xtables\components\TableView\TableView;
use xtables\base\AjDi;
protected function getByAjax() {
$this->params = array_merge($this->params, include 'table.php');
$this->table = new TableView($this->params);
return AjDi::getReply([
View::WORKFLOW => $this->table->get(), // название селектора css, куда вставлять данные ответа
View::WORKFLOW_SEARCH => $this->table->getSearchForm()
]);
}
ajDi
в случае ошибки ответа выведет ее содержание на экран
Также можно использовать ajDi
для кросс доменных запросов (запросов между
разными доменами).
Однако таким образом можно передать только данные в формате json, что является ограничением
технологии в целях безопасности.
Для использования jsonp нужно передать в метод AjDi::getJs
в качестве url адрес, начинающийся
http
или //
.
В методе контроллера, который будет возвращать ответ (будет расположен на другом домене) нужно использовать метод
класса xtables\base\Response
- jsonp($json)
, в который передать данные в формате json.
InfoBox
информация будет отображаться и при использовании кросс-доменных запросов.
Однако иные возможные ответы сервера не будут передаваться и не будут видны на другом домене (сайте), так как являются html содержимым.
callback
, так как он автоматически обрабатывается xTables и используется для
формирования JSONP ответов.
Пример кросс доменных запроса и ответа:
Запрос с домена site-request.ru
use xtables\base\AjDi;
AjDi::getJs('http://site-reply.ru/route/to', $this->params, 300);
//AjDi::getJs('//site-reply.ru/route/to', $this->params, 300); // for use with http and https
Ответ с домена site-reply.ru
use xtables\xTables;
use xtables\base\AjDi;
$reply = AjDi::getReply([
'#some-css-id' => 'any data, html data or other to transfer'
]);
xtables::$response->jsonp($reply);
На клиенте могут быть использованы функции:
В фукнцию xtables.startAjDi()
нужно передать агрументы:
url
- адрес на том же или другом домене;target
- для получения данных локально, можно вместо url
использовать данный параметр (он имеет приоритет, если указан), в котором указать либо
наименование функции либо анонимную функцию, в этом случае произойдет обращение в данную функцию,
ей будут переданы параметры;
функция должна возвратить ответ в виде JS объекта либо строки и он будет обработан также, как будто это ответ от сервера;
data
- необязательно данные, которые будет переданы на сервер;
refresh
- необязательно
время в секундах, через которое должна происходить перезагрузка аякс конетейнера;
reloadBundles
- необязательно
массив с именами селекторов, аякс контейнеры которых должны быть перезагружены (reload без
новых параметров) после выполнения запроса (обычный массив, не json), или строка с именами селекторов через запятую;
history
- необязательно
url адрес для помещения его в историю браузера для обеспечения ajax навигации;
before
- необязательно
функция или строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
(должен быть передан в качестве второго аргумента в xtables.startAjDi()
);
функция будет выполнена первой до всех остальных действий, соответственно функция может, например,
изменить значение каких-то элементов;false
, то дальнейшее выполнение будет остановлено;
after
- необязательно
функция или строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
(должен быть передан в
качестве второго аргумента в xtables.startAjDi()
) и
data
, которые будут получены в качестве ответа от сервера;
по умолчанию полученные данные обрабатываются функцией xtables.serverReplyHandle
,
если функция вернет false
, то данная функция не будет вызвана, это может
быть использовано для переопределения функционала ответа;
$this
- обернутый в jQuery this
// request to server
xtables.startAjDi({
before: function() {
},
after: function() {
},
url: '/some/url',
data: {
some: 'some data',
else: 1
},
refresh: 0,
reloadBundles: ['#selector1', '#selector2'],
history: '/some/new/url'
}, jQuery(this));
// local request to function
xtables.startAjDi({
before: function() {
},
after: function() {
},
target: function(data) {
// some function to handle data and
// return reply similar to server ajDi reply (object or string)
},
// target: 'xtables.someFunc',
// target: 'window.someFunc',
// target: 'someFunc',
data: {
some: 'some data',
else: 1
},
refresh: 0,
reloadBundles: ['#selector1', '#selector2'],
//history: '/some/new/url'
}, jQuery(this));
Эта функция используется для перезагрузки аякс контейнера по имени селектора. Если в фукнцию будут переданы url, data, то произойдет обновление данных ajax dispatcher. Если будет только сообщен селектор, то произойдет простая перезагрузка.
selector
- обязательно наименование селектора по правилам CSS (#, .);
url
- необязательно адрес;
data
- необязательно данные, которые будет переданы на сервер.
xtables.ajDiBundle('#someId');
// or
xtables.ajDiBundle('#someId', '/some/url', {
some: 'some data',
else: 1
});
Эта функция предназначена для перезагрузки ранее загруженного аякс диспетчера. В функцию должны быть переданы именованные параметры:
num
- обязательно
имя аякс диспетчера;
url
- необязательно
адрес на том же или другом домене для изменения соответствующего параметра в ранее загруженном
аякс диспетчере, для простой перезагрузки вводить адрес не нужно;
data
- необязательно
данные, которые заменят передающиеся данных аякс диспетчером данные, для простой перезагрузки вводить
этот параметр не нужно;
history
- необязательно
url адрес для помещения его в историю браузера для обеспечения ajax навигации
xtables.reloadAjDi({num: 'ajDi234'});
// OR
xtables.reloadAjDi({
num: 'ajDi234', // some ajDi name
url: '/some/url',
data: {
some: 'some data',
else: 1
},
history: '/some/new/url'
});
Использование ajax dispatcher может быть осуществлено через data атрибуты ссылки или кнопки.
Для этого достаточно добавить к ним css класс ajax
. В качестве параметров будут использоваться:
href
или data-url
-
адрес для направления аякс запроса, параметры можно добавить в
ссылку; при этом запрос будет отправлен методом POST и к нему будет добавлен csrf токен;data-target
- для получения данных локально, можно вместо url
использовать данный параметр (он имеет приоритет, если указан), в котором указать
наименование функции, в этом случае произойдет обращение в данную функцию,
ей будут переданы параметры (данные из дата параметров);
функция должна возвратить ответ в виде JS объекта либо строки и он будет обработан также, как будто это ответ от сервера;
data-before
- необязательно
строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
ссылки;
функция будет выполнена первой до всех остальных действий, соответственно функция может, например,
изменить значение каких-то элементов;false
, то переход по ссылке не будет осуществлен,
ссылка будет заблокирована, пока функция не перестанет возвращать false
;
data-after
- необязательно
строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
ссылки и
data
, которые будут получены в качестве ответа от сервера;
по умолчанию полученные данные обрабатываются функцией xtables.serverReplyHandle
,
если функция вернет false
, то данная функция не будет вызвана, это может
быть использовано для переопределения функционала ответа;
data-refresh
- необязательно
время для периодического обновления аякс контейнера в секундах;
data-history
- необязательно
для обеспечения аякс навигации нужно использовать данный параметр, в который
передать адрес для изменения истории браузера; если в качестве значения указать url
или href
,
то будет использован адрес, который соответствует url аякс запроса
data-bundles
- необязательно
список селекторов через запятую, аякс конейтнеры которых должны быть перезагружены после
выполнения запроса;
data-...
- все остальные дата параметры будут переданы по роуту или в функцию локально,
если выбран data-target
.
<!-- to server -->
<a class="ajax" href="/some/url?id=1" data-history="url" data-refresh="180"
data-bundles="#selector, #selector2" data-before="xtables.someFunc">Link</a>
<button class="ajax" data-url="/some/url?id=1" data-history="url" data-refresh="180"
data-bundles="#selector, #selector2" data-before="xtables.someFunc">Button</button>
<!-- local to function -->
<a class="ajax" href="#" data-target="someFunc" data-refresh="180"
data-bundles="#selector, #selector2" data-before="xtables.someFunc">Link</a>
Использование ajax dispatcher на html формах может быть осуществлено через data атрибуты формы.
Для этого достаточно добавить к ним css класс ajax-form
.
input[type='submit']
, либо через button[type='submit']
.
@since version 1.7.22
если необходимо, чтобы форма была передана локально в функцию, то вместо
url
нужно использовать параметр data-target
(он имеет приоритет, если указан), в котором указать
наименование функции, в этом случае произойдет обращение в данную функцию,
ей будут переданы параметры (данные из дата параметров и поля формы (input, textarea, checkbox, radio, select));
функция должна возвратить ответ в виде JS объекта либо строки и он будет обработан также, как будто это ответ от сервера.
Таким образом, поведение не изменится лишь за тем исключением, что все данные будут направлены
не на сервер по роуту, а в функцию.
Также в функцию, определенную в data-target
, в параметре $this
будет передан обернутый в jQuery this,
соответствующий форме (тегу form
).
Имеется возможность шифрования передаваемых на сервер в полях типов input, textarea
значений, используя открытый ключ RSA. Использование шифрования в ajax формах
происходит максимально просто и незаметно. Достаточно добавить к нужному полю
input, textarea css класс crypt
. При отправке содержимое поля
будет заменяться на ***CRYPT***
.
Длина передаваемых в шифруемом поле данных не должна превышать 465 символов.
Для формирования полей, обязательных к заполнению, в input, textarea таких аякс форм
можно добавить класс .required
.
<-- to server -->
<form action="/some/url" class="ajax-form">
<div class="form-group">
<input type="text" name="some_name" class="form-control required"> <!--prevent to submit if empty-->
</div>
<div class="form-group">
<input type="text" name="else_name" class="form-control crypt"> <!--will be crypted-->
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">
Send
</button>
</div>
</form>
<-- local to function -->
<form data-target="someFunc" data-id="243" class="ajax-form">
<div class="form-group">
<input type="text" name="some_name" class="form-control required"> <!--prevent to submit if empty-->
</div>
<div class="form-group">
<input type="text" name="else_name" class="form-control crypt"> <!--will be crypted-->
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">
Send
</button>
</div>
</form>
Для обозначения шифруемых полей input можно воспользоваться фукнционалом, предоставляемым css фреймворком Bootstrap.
В качестве параметров могут использоваться:
data-before
- необязательно
строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
формы;
функция будет выполнена первой до всех остальных действий, соответственно функция может, например,
изменить значение каких-то элементов;false
, то форма не будет отправлена;
data-after
- необязательно
строка с именем функции, может содержать название объекта через точку, из строки будет извлечена
ссылка на объект и функцию;this
формы и
data
, которые будут получены в качестве ответа от сервера;
по умолчанию полученные данные обрабатываются функцией xtables.serverReplyHandle
,
если функция вернет false
, то данная функция не будет вызвана, это может
быть использовано для переопределения функционала ответа;
action
- обязательно
адрес для направления аякс запроса;
при этом запрос будет отправлен методом POST и к нему будет добавлен csrf токен;
data-timer
- необязательно
после отправки запроса кнопка (инпут submit) блокируются, для
показа таймера на ней можно воспользоваться данным параметром, определив его со значением 1
;
data-refresh
- необязательно
время для периодического обновления аякс контейнера в секундах;
data-history
- необязательно
для обеспечения аякс навигации нужно использовать данный параметр, в который
передать адрес для изменения истории браузера; если в качестве значения указать url
или href
,
то будет использован адрес, который соответствует url аякс запроса
data-bundles
- необязательно
список селекторов через запятую, аякс конейтнеры которых должны быть перезагружены после
выполнения запроса;
<form class="ajax-form" action="/some/url" data-timer="1" data-before="xtables.someFunc">
<input type="text" name="some_name">
<input type="text" name="some_name2">
<input type="text" name="some_name3" class="crypt"> <!--{will be crypted}-->
<button>
Submit this form
</button>
</form>
При использовании ajDi
поведение ключевых компонентов xTables: TableView, CardView, CardNew,
изменяется.
В TableView пагинация и сортировка начинают обрабатываться через ajax запросы с загрузкой в те же элементы DOM тем же
ajDi
, ссылки в таблице, которым присвоен css класс 'ajax'
будут вызывать ajax dispatcher по указанному в них адресу.
Если компонент загружен без использования ajDi
, то все ссылки сохрянят свое обычное поведение и будут
обеспечивать переход по указанному в них адресу.
ajDi
будет загружать содержимое в те селекторы, которые будут сообщены
в массиве, аналогичном передаваемому при создании первоначального диспетчера (правильный массив может быть создан с использованием
метода xtables\base\AjDi::getReply()
).
/
json_encoded, base64_encoded строку.
/incoming/card/eyJpZCI6IjU0NTUifQ==
.
В CardView при использовании ajDi
при редактировании карточки сохранение будет происходить с использованием
того же диспетчера, что и первоначально загружал компонент и соответственно в том же элементе DOM.
В CardNew при использовании ajDi
при сохранении новой записи, созданная карточка будет открыта с использованием
того же диспетчера, что и первоначально загружал компонент и соответственно в том же элементе DOM.
Настройки осуществляются путем передачи параметров в методы, описано выше.