4.4.2. DropDownMapper
В статье о JavaScript классе
AjaxDropdownPreloader, рассматривалось
взаимодействие между двумя выпадающих меню (далее ВМ):
первое ВМ - главное;
второе ВМ - зависимое.
По мере необходимости возможно подключить любое количество зависимых ВМ, причем каждое новое зависимое ВМ
означает создание нового объекта класса
AjaxDropdownPreloader. Сложность кода
будет расти и логика становиться менее прозрачной. В результате выгода от использования AjaxDropdownPreloader
становится спорной.
Класс AjaxDropdownPreloader является оптимальным решением только в случае использования с двумя ВМ
(главным - зависимым). А рассматриваемый в данной статье JavaScript класс DropDownMapper специально создан
для реализации связи между тремя и более ВМ. Класс DropDownMapper реализует связь между множеством ВМ,
используя массив экземпляров класса AjaxDropdownPreloader.
Параметры инициализации
Для успешной реализации связи между многими ВМ необходимо создать экземпляр класса DropDownMapper, передав
ему параметры, описанные в приведённой ниже таблице.
название |
описание |
|---|---|
| map (object) | Данный параметр представляет из себя 'UniqueKey' : {
'Field' : 'FieldName',
'Pass' : [<field_names>],
'Value' : 'SelectedValue',
'Dependent' : false,
'SubNodes' : { }
}
Примечание Названия ключам, используемым для идентификации объектов полей можно давать любые, главное, чтобы они были уникальными в пределах своего уровня вложенности. |
| request (string) | Ссылка, при заходе на которую будет возвращён XML документ, содержащий новый набор опций для зависимого ВМ. XML документ должен быть в следующем формате: <field_options>
<option>ID1</option>
<option>ID2</option>
</field_options>
Стоит обратить особое внимание на то, что XML документ содержит только |
| input_mask (string) | Маска для получения любого элемента ввода на форме. Обычно маска получается путём вызова тэга
InputName со значением <inp2:prefix_InputName field="#FIELD_NAME#"/>
// вернёт строку вида: prefix[ID][#FIELD_NAME#]
|
Настройка шаблона редактирования
Для подключения класса DropDownMapper на форму достаточно получить его экземпляр с правильно переданными
параметрами, в одном из которых и нужно определить зависимость между множеством ВМ. Для примера рассматривается
ситуация, в которой ВМ от полей Field_11 и Field_12 зависят от значения поля Field_1, а
ВМ Field_111 зависит от значения поля Field_11.
После выполнения приведённых ниже шагов настройку шаблона можно считать завершённой.
Добавить на форме элементы ВМ:
<inp2:m_RenderElement name="inp_edit_options" prefix="sample-prefix" field="Field_1" title="la_fld_Field_1"/>
<inp2:m_RenderElement name="inp_edit_options" prefix="sample-prefix" field="Field_11" title="la_fld_Field_11"/>
<inp2:m_RenderElement name="inp_edit_options" prefix="sample-prefix" field="Field_12" title="la_fld_Field_12"/>
<inp2:m_RenderElement name="inp_edit_options" prefix="sample-prefix" field="Field_111" title="la_fld_Field_111"/>
Добавить вызов класса
DropDownMapperпередав ему все требуемые параметры:
var $mapping = {
'Level_1' : {
'Field' : 'Field_1',
'Dependent' : false,
'SubNodes' : {
'Level_11' : {
'Field' : 'Field_11',
'SubNodes' : {
'Level_111' : { 'Field' : 'Field_111' }
}
},
'Level_12' : {
'Field' : 'Field_12'
}
}
}
};
new DropDownMapper(
$mapping,
'<inp2:m_Link template="dummy" pass="m,sample-prefix" sample-prefix_event="OnGetDropDownXML" q="#QUESTIONED#" f="#FILTERS#" no_amp="1"/>',
'<inp2:sample-prefix_InputName field="#FIELD_NAME#"/>'
);
Настройка обработчика событий
В метод OnGetDropDownXML необходимо добавить функциональность для получения опций ВМ каждого конкретного случая:
/**
* [AJAX] Метод для получения отфильтрованных опций в виде XML документа.
*
* @param kEvent $event
*/
function OnGetDropDownXML(&$event)
{
$event->status = erSTOP;
if ($this->Application->GetVar('ajax') != 'yes') {
return ;
}
// $q поле соответствующие зависимому ВМ, для которого в данный момент вычисляются опции.
$q = $this->Application->GetVar('q');
$f = $this->Application->GetVar('f');
parse_str($f, $filters);
// $filters массив, где ключи это поля соответствующих ВМ, а значения выбранные опции из соответствующих ВМ
// Все необходимые фильтры для SQL запроса в массиве $filters
// Ниже требуется составить SQL для каждого конкретного случая
switch ($q) {
case 'Field_12':
$sql = 'SELECT ...
FROM ...
WHERE ...';
break;
case 'Field_11':
$sql = 'SELECT ...
FROM ...
WHERE ...';
break;
case 'Field_111':
$sql = 'SELECT ...
FROM ...
WHERE ...';
break;
}
if (!$sql) {
return ;
}
$data = $this->Conn->Query($sql);
if (!$data) {
return ;
}
$o = '';
foreach ($data as $row) {
$attributes = '';
foreach ($row as $field => $value) {
if ($field == 'Value' || $field == 'Name') {
continue;
}
$attributes .= $field . '="' . htmlspecialchars($value) . '" ';
}
$o .= '<option value="' . htmlspecialchars($row['Value']) . '" ' . $attributes .'><![CDATA[' . $row['Name'] . ']]></option>';
}
$this->Application->XMLHeader();
echo '<field_options>' . $o . '</field_options>';
}
Событие OnGetDropDownXML необходимо добавить в метод mapPermissions,
который обеспечит проверку наличия у пользователя необходимых прав доступа для вызова данного события:
/**
* Метод связывающий события и права, необходимые для их выполнения.
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnGetDropDownXML' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
Совет
Также следует обратить внимание на некоторые, описанные ниже, приёмы, которые использовались при
написании события OnGetDropDownXML.
В начале события рекомендуется установить статус его выполнения в erSTOP. Это укажет на то, что по окончания выполнения события не нужно показывать содержание переданного шаблона (в данном случае это
dummy):
$event->status = erSTOP;
В начале события написать код, который позволит игнорировать запросы, которые будут делать поисковые системы:
if ($this->Application->GetVar('ajax') != 'yes') {
return ;
}
Параметр ajax добавляется автоматически при отправлении каждого
AJAX запроса. Если поисковая система где-то найдёт ссылку, в
которой указано данное событие, то зайдя на неё тело события выполнено не будет.
Перед выводом XML документа на экран необходимо послать браузеру соответствующий заголовок. Сделать это можно при помощи метода
Application::XMLHeader:
$this->Application->XMLHeader();
См. также