Отображение данных в виде списков в Bitrix24

В первую очередь bitrix24 предназначен для работы с данными, какими бы они не были. В 99% случаев эти данные нужно отображать в виде списка с определенным набором функций (какие-то действия над элементами списка, постраничная навигация, поиск и тд). В этой статье я расскажу как с помощью штатных средств быстро создать список элементов с требуемым функционалом.

Если вам уже посчастливилось работать с bitrix24, то вероятно вы уже знакомы с используемым в системе способом отображения списочных данных. Компонент для отображения данных в табличном виде называется grid и выглядит следующем образом:

В основе примера используются компоненты для отображения панели фильтрации, кнопок управления и сам grid (bitrix:main.ui.grid). Попробуем реализовать компонент для отображения собственных элементов. В роли собственных элементов будут выступать пользователи портала, источником данных будет ORM модель \Bitrix\Main\UserTable.

Шаг 1 Создание структуры компонента

Начнём с создания структуры компонента. В директории /local/components/aclips/ создадим следующие файлы и каталоги:

- local/components/aclips/
-- base.grid/
--- class.php
--- templates/
----.default/
----- template.php

Шаг 2 Логика компонента

Всё поведение компонента описывается в файле class.php. Это будет класс, расширяющий базовый \CBitrixComponent. Для начала создадим «болванку», которую в дальнейшем будем дорабатывать:

<?php
namespace Aclips\Components;


class BaseGridComponent extends \CBitrixComponent
{
    const GRID_ID = 'BASE_GRID';

    const PAGE_SIZE = 15;

    public function executeComponent()
    {
        $this->includeComponentTemplate();
    }
}

Краткое описание методов класса BaseGridComponent (типизация входных параметров и выходных значений не указана):

  • public function executeComponent() — основной код компонента;
  • public function getEntityRepository() — возвращает объект сущности (репозиторий) для получения данных;
  • public function initNav($grid_options, $page_size) — получение объекта для постраничной навигации;
  • public function getSorting($grid) — получение сортировки;
  • public function getEntityFilter($grid_id, $grid_filter) — получение объекта для фильтрации;
  • public function getEntitySelect() — получение списка полей, которые будут участвовать в выборке;
  • public function getPreparedElement($fields) — метод для преобразования элементов
  • public function getElementActions($fields) — получение действий для выполнения над элементом;
  • private function getFilterFields($option = []) — получение полей фильтра;
  • private function getGridColumns($option = []) — получение полей списка;
  • private function prepareFilter($grid_id, $grid_filter) — преобразование данных, полученных из фильтра.

Константы класса:

  • const GRID_ID — идентификатор списка (грида);
  • const PAGE_SIZE — количество элементов, отображаемое на одной странице;

Подробнее остановимся только на некоторых методах.

Метод executeComponent

Работа данного метода сводится к получению и обработке данных, которые будут переданы в стандартные компоненты отображения фильтра и списка в шаблоне компонента.

public function executeComponent()
{
    $grid_id = self::GRID_ID;
    $grid_options = new Grid\Options($grid_id);

    $grid_filter = $this->getFilterFields();

    $entityRepository = $this->getEntityRepository();

    $filter = $this->getEntityFilter($grid_id, $grid_filter);

    $select = $this->getEntitySelect();

    $sort = $this->getSorting($grid_options);

    $page_size = $this->arParams['PAGE_SIZE'] ?? self::PAGE_SIZE;
    $nav = $this->initNav($grid_options, $page_size);

    $elements = $entityRepository::getList([
        'filter' => $filter,
        'select' => $select,
        "order" => $sort,
        "count_total" => true,
        "offset" => $nav->getOffset(),
        "limit" => $nav->getLimit()
    ]);

    $nav->setRecordCount($elements->getCount());

    $grid_rows = [];

    foreach ($elements as $element) {
        $prepared_element = $this->getPreparedElement($element);

        $actions = $this->getElementActions($element);

        $row = [
            'id' => $element['ID'],
            'data' => $element,
            'columns' => $prepared_element,
            'editable' => 'Y',
            'actions' => $actions
        ];

        $grid_rows[] = $row;
    }

    $this->arResult['NAV'] = $nav;

    $this->arResult['GRID_ID'] = $grid_id;
    $this->arResult['GRID_FILTER'] = $grid_filter;
    $this->arResult['GRID_COLUMNS'] = $this->getGridColumns();
    $this->arResult['ROWS'] = $grid_rows;

    $this->includeComponentTemplate();
}
Метод getEntityRepository

Возвращает объект, отдающий данные. В зависимости от best replica watcheshttps://www.jana-fuchs.de/salon/article source типа объекта, реализация в методе executeComponent может меняться. В нашем примере мы используем объект от типа \Bitrix\Main\ORM\Data\DataManager.

public function getEntityRepository()
{
    $entityReporitory = new \Bitrix\Main\UserTable();

    return $entityReporitory;
}
Метод getPreparedElement

Для обработки сырых (полученных из бд) данных каждый элемент попадает в данный метод. Например, у нас есть поле ACTIVE со значениями Y и N, а в списке мы хотим отображать словами «Пользователь активен» или «Пользователь не активен»

public function getPreparedElement($fields)
{
    $fields['ACTIVE'] = $fields['ACTIVE'] == 'Y' ? 'Пользователь активен' : 'Пользователь не активен';
  
    return $fields;
}
Метод getElementActions

Как уже было сказано, метод возвращает массив действий над записями. Каждый элемент действий содержит 3 свойства:

  • text — название действия, отображаемое в контекстном меню;
  • onclick — js действие, выполняемое при выборе пункта;
  • default — флаг, отвечающий за действие, выполняемое при двойном клике по записи в списке.
public function getElementActions($fields)
{
    $actions = [];

    $actions[] = [
        'text' => 'Открыть',
        'onclick' => "alert('Выбран пункт Открыть')",
        'default' => true
    ];

    $actions[] = [
        'text' => 'Удалить',
        'onclick' => "alert('Выбран пункт Удалить')",
    ];
    
    return $actions;
}
Метод getFilterFields

Возвращает массив элементов, которые должны отображаться в фильтре. Состоят элементы из:

  • id — Идентификатор поля фильтра;
  • name — Отображаемое название;
  • type — Тип поля (влияет на способ отображения);
  • default — флаг, отвечающий за отображение поля в фильтре по умолчанию.

У каждого типа могут быть свои дополнительные параметры.

private function getFilterFields()
{
    $filterFields = [
        [
            'id' => 'NAME',
            'name' => 'Имя',
            'default' => true
        ],
        [
            'id' => 'ACTIVE',
            'name' => 'Активность пользователя',
            'type' => 'list',
            'items' => [
                'Y' => 'Пользователь активен',
                'N' => 'Пользователь не активен'
            ],
            'params' => [
                'multiple' => 'Y'
            ],
            'default' => true
        ],
        [
            'id' => 'DATE_REGISTER',
            'name' => 'Дата регистрации',
            'type' => 'date',
            'default' => true
        ]
    ];

    return $filterFields;
}
Метод getGridColumns

Массив отображаемых полей, содержащих:

  • id — Идентификатор поля;
  • name — Отображаемое название в списке;
  • sort — Идентификатор поля, по которому будет проводиться сортировка;
  • default — Флаг, отвечающий за отображение в списке по умолчанию.
private function getGridColumns()
{
    $columns = [
        [
            'id' => 'NAME',
            'name' => 'Имя',
            'sort' => 'NAME',
            'default' => true
        ],
        [
            'id' => 'ACTIVE',
            'name' => 'Активность',
            'sort' => 'ACTIVE',
            'default' => true
        ],
        [
            'id' => 'DATE_REGISTER',
            'name' => 'Дата регистрации',
            'sort' => 'DATE_REGISTER',
            'default' => true
        ]
    ];

    return $columns;
}
Метод prepareFilter

Формирует из полученных данных массив для фильтрации элементов.

Пример:

private function prepareFilter($grid_id, $grid_filter): array
{
    $filter = [];

    $filterOption = new \Bitrix\Main\UI\Filter\Options($grid_id);
    $filterData = $filterOption->getFilter([]);

    foreach ($filterData as $k => $v) {
        $filter[$k] = $v;
    }

    $filterPrepared = \Bitrix\Main\UI\Filter\Type::getLogicFilter($filter, $grid_filter);

    if (!empty($filter['FIND'])) {
        $findFilter = [
            'LOGIC' => 'OR',
            [
                '%NAME' => $filter['FIND']
            ]
        ];

        if (!empty($filterPrepared)) {
            $filterPrepared[] = $findFilter;
        } else {
            $filterPrepared = $findFilter;
        }
    }

    return $filterPrepared;
}

Шаг 3 Шаблон отображения

Логики описаны, данные получены. Остаётся передать сформированные параметры в компоненты, отвечающие за построение фильтра (bitrix:main.ui.filter) и списка (bitrix:main.ui.grid).

Фильтр

На момент написания статьи доступен еще один способ отображения фильтра, через Toolbar модуля ui. Мне этот способ нравится больше, по этому рассматривать в примере будем именно его.

Добавим в шаблон код:

 <?php

/**
 * Toolbar filter
 **/
\Bitrix\Main\Loader::includeModule('ui');

\Bitrix\UI\Toolbar\Facade\Toolbar::addFilter([
    'FILTER_ID' => $arResult['GRID_ID'],
    'GRID_ID' => $arResult['GRID_ID'],
    'FILTER' => $arResult['GRID_FILTER'],
    'ENABLE_LIVE_SEARCH' => true,
    'ENABLE_LABEL' => true
]);

Данный способ удобен тем, что на страницу добавляется компонент, в который можно без особого труда добавить какие-либо элементы управления.

Для добавления кнопки рядом с полем ввода нужно создать экземпляр этой самой кнопки и передать её в Toolbar.

/**
 * Toolbar buttons
 **/
$addButton = new \Bitrix\UI\Buttons\AddButton([
    "click" => new \Bitrix\UI\Buttons\JsCode(
        "alert('Кнопка нажата')"
    ),
    "text" => "Важная кнопка"
]);

\Bitrix\UI\Toolbar\Facade\Toolbar::addButton($addButton);

Подробнее ознакомиться с кнопками и прочими элементами интерфейса можно в документации.

Список

Вызываем компонент списка и передаём в него параметры. У компонента настроек много и описывать их в данной статье не имеет смысла. При желании и небольшом усилии можно легко разобраться за что отвечает каждый из параметров :).

Код вызова штатного компонента списка:

<?php $APPLICATION->IncludeComponent('bitrix:main.ui.grid', '', [
    'GRID_ID' => $arResult['GRID_ID'],
    'COLUMNS' => $arResult['GRID_COLUMNS'],
    'ROWS' => $arResult['ROWS'],
    'NAV_OBJECT' => $arResult['NAV'],
    'AJAX_MODE' => 'Y',
    'AJAX_ID' => \CAjax::getComponentID('bitrix:main.ui.grid', '.default', ''),
    'AJAX_OPTION_JUMP' => 'N',
    'SHOW_ROW_CHECKBOXES' => false,
    'SHOW_CHECK_ALL_CHECKBOXES' => false,
    'SHOW_ROW_ACTIONS_MENU' => true,
    'SHOW_GRID_SETTINGS_MENU' => true,
    'SHOW_NAVIGATION_PANEL' => true,
    'SHOW_PAGINATION' => true,
    'SHOW_SELECTED_COUNTER' => false,
    'SHOW_TOTAL_COUNTER' => false,
    'SHOW_PAGESIZE' => false,
    'SHOW_ACTION_PANEL' => false,
    'ALLOW_COLUMNS_SORT' => true,
    'ALLOW_COLUMNS_RESIZE' => true,
    'ALLOW_HORIZONTAL_SCROLL' => true,
    'ALLOW_SORT' => true,
    'ALLOW_PIN_HEADER' => true,
    'AJAX_OPTION_HISTORY' => 'N',
    "ENABLE_COLLAPSIBLE_ROWS" => true
], $component); ?>

Итог

Описанным выше способом можно собрать базовый компонент, который сэкономит очень много времени, нервов и сил. Сам компонент можно скачать из репозитория. Обращаю внимание, что это всего лишь «шаблонный» компонент, используя который можно решить свои задачи. Опираясь на него я продемонстрирую, как я использую javascript в компонентах bitrix24 в следующих статьях.

Добавить комментарий