При разработке системы, в которой пользователи будут проводить большую часть своей жизни, интерактивные интерфейсы и динамическая работа с контентом занимают далеко не последнее место. Ко всему прочему при кастомизации Bitrix24 будет сложно обойти эти моменты стороной. В этой статье мы немного погрузимся в js, посмотрим на стандартные инструменты, предоставляемый ядром и попытаемся организовать код для работы с frontend’ом компонента в удобном виде.
Продолжим работу над компонентом, который мы создали в статье Отображение данных в виде списков в Bitrix24. При выборе пунктов контекстного меню ничего сейчас не происходит. Будем исправлять 🙂
Шаг 1 Файл script.js
Для подключения js в компоненте нужно создать файл с названием script.js в директории с шаблоном компонента. Файл будет загружен автоматически при вызове компонента (при условии, что указан нужный шаблон).
- local/components/aclips/
-- base.grid/
--- class.php
--- templates/
----.default/
----- template.php
----- script.js
Добавим в script.js произвольный код и убедимся, что при загрузке страницы с вызываемым компонентом код отработал.
alert('script.js подключен')
Шаг 2 Объект и namespace
В файле скрипта можно указывать произвольный код, перечень функций и вообще всё, что сможет корректно отработать. Но такой подход сильно усложняет чтение, отладку и последующие доработки кода. Я предпочитаю создавать объект, который будет в себе содержать все свойства и методы, относящиеся к конкретному компоненту. Таким образом код
let gridId = '' function createElement() { ... } function reloadComponentGrid(gridId) { ... }
превращается в понятный и структурированный
let componentObject = { gridId: '', createElement: function() { ... }, reloadComponentGrid: function(){ // Используем свойство объекта this.gridId } }
Согласитесь, что название componentObject не самый лучший и очевидный вариант именования. В Bitrix24 объекты распределены в пространстве имён BX., что позволяет случайно не наткнуться на переопределение существующего функционала и вносит некоторую ясность в то, с чем мы работаем в данный момент. Гораздо лучше будет хранить наш объект в пространстве имён BX.Aclips.BaseGrid.List.
Для создания такой цепочки объектов в js библиотеке Bitrix предусмотрен метод BX.namespace(namespaceName: string). Этот метод создаст требуемыое пространство имён, если оно отсутствует и вернёт на него ссылку.
BX.namespace('Aclips.BaseGrid.List') BX.Aclips.BaseGrid.List = { gridId: '', createElement: function() { ... }, reloadComponentGrid: function(){ // Используем свойство объекта this.gridId } }
Шаг 3 Инициализация
При работе нам могут понадобиться какие-либо параметры, к примеру идентификатор грида, шаблон ссылки профиля пользователя и тд. Мы можем их указать напрямую в шаблоне сайта:
<script> BX.ready(function() { BX.Aclips.BaseGrid.List.gridId = 'Идентификатор грида' BX.Aclips.BaseGrid.List.pathTemplates = { userProfile: '/company/personal/user/#ID#/' } }) </script>
Альтернативным вариантом будет добавление метода init(), который будет принимать объект с параметрами, распределять их по нужным свойствам. Также init может выполнять прочие действия, требуемые для работы функционала. Иными словами — создадим конструктор нашего объекта.
Файл template.php
... <script> BX.ready(function() { let componentParams = { gridId: 'Идентификатор грида', pathTemplates: { userProfile: '/company/personal/user/#ID#/' } } BX.Aclips.BaseGrid.List.init(componentParams) }) </script>
Файл script.js
BX.namespace('Aclips.BaseGrid.List') BX.Aclips.BaseGrid.List = { gridId: null, pathTemplates: {}, init: function(params) { // @TODO проверка существования и корректности значений this.gridId = params.gridId this.pathTemplates = params.pathTemplates } }
Шаг 4 Добавление методов
В компоненте списка были добавлены пункты меню для каждого элемента. Добавим в js объект методы для открытия и удаления элементов.
Открытие профиля пользователя
BX.namespace('Aclips.BaseGrid.List') BX.Aclips.BaseGrid.List = { ... openProfile: function(userId) { let profileUrl = this.pathTemplates.userProfile.replace('#ID#', userId) BX.SidePanel.Instance.open(profileUrl); }, }
При вызове BX.Aclips.BaseGrid.List.openProfile(1) будет открыт профиль пользователя с помощью штатной библиотеки BX.SidePanel в слайдере (подробнее ознакомиться со свойствами и возможностями слайдера можно здесь).

Удаление пользователя
Удаление пользователя будет состоять из нескольких действия:
- Окно подтверждения удаления (showRemoveUserConfirmation)
- Ajax запрос на удаление пользователя (removeUser)
- Перезагрузка грида (reloadGrid)
BX.namespace('Aclips.BaseGrid.List') BX.Aclips.BaseGrid.List = { ... showRemoveUserConfirmation: function (userId) { let self = this BX.PopupWindowManager.create("popup-remove-user-confirmation", null, { titleBar: 'Удаление пользователя', content: 'Вы точно хотите удалить пользователя?', autoHide: true, overlay: { backgroundColor: 'black', opacity: 500 }, buttons: [ new BX.PopupWindowButton({ text: 'Да', id: 'accept-btn', className: 'ui-btn ui-btn-success', events: { click: function () { let callback = () => { self.reloadGrid() this.popupWindow.close() } self.removeUser(userId, callback) } } }), new BX.PopupWindowButton({ text: 'Отмена', id: 'decline-btn', className: 'ui-btn ui-btn-danger', events: { click: function () { this.popupWindow.close() } } }) ], events: { onPopupClose: function () { this.destroy() } } }).show() }, removeUser: function (userId, callback) { // Ajax запрос на удаление пользователя if (callback && {}.toString.call(callback) === '[object Function]') { callback() } }, reloadGrid() { let grid = BX.Main.gridManager.getById(this.gridId); if (grid) { grid.instance.reload() } } }
Вызов метода BX.Aclips.BaseGrid.List.showRemoveUserConfirmation(1) отобразит окно подтверждения удаления. По нажатию на кнопку «ДА» будут выполнены удаление и callback функция, которая в нашем примере перезагружает список и закрывает окно подтверждения. (Способ отправки данных через ajax и обработка ответа будут рассмотрены в следующей статье).
let callback = () => { self.reloadGrid() this.popupWindow.close() }

Всплывающее окно реализовано через библиотеку BX.PopupWindowManager.
Мне больше UI.Diaglos по душе…
Андрей Николаев
Шаг 5 Подключение обработчиков в компоненте
Пропишем вызов реализованных выше методов в классе компонента, после чего при выборе пунктов контекстного меню элементов будут выполняться необходимые действия
public function getElementActions($fields) { $actions = []; $actions[] = [ 'text' => 'Открыть', 'onclick' => "BX.Aclips.BaseGrid.List.openProfile({$fields['ID']})", 'default' => true ]; $actions[] = [ 'text' => 'Удалить', 'onclick' => "BX.Aclips.BaseGrid.List.showRemoveUserConfirmation({$fields['ID']})", ]; return $actions; }
Итог
Подобным образом можно реализовать любую логику и не боятся, что через день/неделю/месяц появится необходимость вносить в неё изменения. Каждое действие находится на своём месте и не зависит от других, что позволяет вносить правки без опасений сломать другую часть функционала.