При разработке системы, в которой пользователи будут проводить большую часть своей жизни, интерактивные интерфейсы и динамическая работа с контентом занимают далеко не последнее место. Ко всему прочему при кастомизации 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 функция, которая в нашем примере перезагружает список и закрывает окно подтверждения. (Способ отправки данных flaunt phone case через 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;
}Итог
Подобным образом можно реализовать любую логику и не боятся, что через день/неделю/месяц появится необходимость вносить в неё изменения. Каждое действие находится на своём месте и не зависит от других, что позволяет вносить правки без опасений сломать другую часть функционала.