JavaScript в компонентах Bitrix24

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

Итог

Подобным образом можно реализовать любую логику и не боятся, что через день/неделю/месяц появится необходимость вносить в неё изменения. Каждое действие находится на своём месте и не зависит от других, что позволяет вносить правки без опасений сломать другую часть функционала.

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