Скрипты в виджетах

Виджеты — это один из базовых элементов построения интерфейса. Виджеты могут создаваться и быть доступны в рамках раздела или приложения, а также быть общими для всей компании. Подробнее о виджетах можно узнать в статье «Создание интерфейсов».

Для выполнения кода, который может осуществлять сложную логику работы с объектами системы или управлять данными и внешним видом виджета, используются сценарии. Код сценария может представлять собой набор функций, пользовательских классов, интерфейсов, написанных на языке TypeScript.

По назначению исполнения сценарии в виджетах делятся на:

  • Клиентские — исполняются в браузере клиента, ограничены правами пользователя, под которым запускаются;

  • Серверные — исполняются на сервере с правами администратора, но имеют ограничение по количеству выполняемых функций в минуту.

Доступ к данным. Роли виджетов

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

Общие виджеты

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

    Context.data.string_1 = 'string value';

Виджеты уровня раздела и приложения

Виджеты могут быть созданы в интерфейсах раздела. Тогда они будут считаться виджетами уровня раздела и будут доступны другим виджетам этого раздела. Также виджеты могут быть созданы на уровне отдельного приложения, то есть в интерфейсах данного приложения. Тогда они будут доступны для других виджетов этого приложения, а также для виджетов раздела, в котором оно находится. Однако, независимо от уровня, для каждого виджета доступны свойства только его собственного контекста.

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

Виджеты форм

Для приложений и бизнес-процессов могут быть созданы пользовательские формы. Для каждой пользовательской формы автоматически создается самостоятельный виджет, который закрепляется за этой формой. Виджеты форм тоже имеют основной контекст Context, но он содержит свойства того объекта, формой которого является данный виджет. Например, если виджет является формой приложения, то в контексте ему доступны свойства данного приложения. То же самое для форм в процессах: в их виджетах доступны свойства контекста бизнес-процесса.

Помимо основного контекста, виджеты форм имеют еще View-контекст, доступный в сценариях по константе ViewContext. View-контест в данном случае содержит свойства, добавленные непосредственно в самом виджете формы. Отсюда следует, что виджеты форм одного приложения или процесса объединены общим контекстом свойств этого приложения или процесса, но View-контекст у каждого виджета свой.

    const itemName = Context.data.__name;
    ViewContext.data.string_1 = `Название ${ itemName }}`;

Функции

Сценарии в виджетах представляют собой набор функций. При загрузке виджета загружаются и транслируются (преобразуются) в JavaScript сценарии, формируется контекст. Непосредственный запуск (исполнение) конкретных функций происходит по отдельности в момент вызова.

Системные функции

В виджетах существуют системные функции, которые запускаются автоматически в определённые ключевые моменты, предусмотренные в системе. Для того чтобы вместе с этим запускалась описанная в сценариях функция, необходимо назначить для нее сопоставление в конструкторе виджета на вкладке Настройки в разделе Системные функции.

  • Инициализация — функция, запускаемая при инициализации виджета. Может быть использована для инициализации стартовых значений свойств контекста, получения необходимых данных, определения внешнего вида виджета при загрузке, а также запуска других функций при загрузке виджета.

Пример использования:

async function onInit (): Promise<void> {
    Context.data.counter = 0;
    setStartValues();
}
  • Необходимость отображения — функция, запускаемая перед рендером виджета и определяющая, будет ли он отображен. Функция должна возвращать значение типа boolean. Если функция возвращает false, то рендер виджета отменяется.

Пример использования:

async function canRender (): Promise<void> {
    return !!Context.data.app;
}
  • Валидация — пользовательская функция валидации. Запускается формой создания или редактирования при сохранении элемента приложения вместе со стандартной валидацией формы. Функция должна возвращать объект результата валидации типа ValidationResult. Если данный объект не будет содержать ошибок, то пользовательская валидация будет считаться успешной и сохранение или изменение элемента будет продолжено. Если объект будет содержать хотя бы одно сообщение об ошибке, то сохранение или изменение будет прервано. Функция валидации запускается в основном виджете формы, а также по всем вложенным виджетам, если у них описана функция валидации. Результаты валидации всех виджетов суммируются и показываются на форме.

Пример использования:

async function validation (): Promise<ValidationResult> {
    const result = new ValidationResult();
    if (!Context.data.stroka || Context.data.stroka.length < 10) {
        result.addContextError('stroka', 'Значение должно быть длиной не менее 10 символов');
    }
    return result;
}

Пользовательские функции

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

async function onInit (): Promise<void> {
    const result = getValues();
    ...
}

function getValues (): Promise<any> {
    return {
        property_1: Context.data.prop1,
        property_2: `some string`,
    };
}

Вызов серверной функции из клиентского сценария

Чтобы запустить выполнение серверной функции не напрямую, а при выполнении клиентской, используйте константу Server.

Серверная функция:

async function DoSomeWork() : Promise<void> {
    // Здесь задана обычная логика серверного сценария
    // Можно также использовать внешние вызовы через `await`
    let response = await fetch('https://my-service.mycompany.com/getmydata?token=' + Context.data.secureToken);
    Context.data.mySecureData = await response.text();
}

Клиентская функция:

async function onButtonClick() : Promise<void> {
    ViewContext.data.blockUI = true;
    await Server.rpc.DoSomeWork();
    ViewContext.data.blockUI = false;
}

Вызов функции дочерними виджетами

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

Здесь мы можем выбрать тип функции (Клиент или Сервер), а затем выбрать функцию из предлагаемого списка.

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

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

Вызов из виджета «Код»

Для вызова клиентского сценария из виджета Код можно использовать конструкцию <%= Scripts %>.ИМЯ_ФУНКЦИИ():

    <button onclick="<%= Scripts%>.OpenPopup()">open popup</button>

Используя вызов функции из сценариев в атрибуте элемента, например onclick, можно передать только строку, но не какой-либо объект целиком. Например:

    <button onclick="<%= Scripts%>.check('<%= someObject.__id %>')">Выполнить</button>

Вызов функции в файле виджета

Для виджетов есть возможность загружать файлы. Если загрузить в виджет файл с JS-кодом, то можно вызвать функцию из файла. Для этого необходимо в виджете Код подключить JS-файл из файлов виджета. Например:

    <script type="text/javascript" src="<%= UI.widget.filePath %>/test2.js"></script>
    <button type="button" onclick="onClickAction()">Кнопка</button>