﻿# Отслеживание событий в поле типа «Таблица»

> [HTML Version](table-events.html)

Вы можете привязать выполнение скрипта к событиям таблицы. Он запустится при действиях пользователя с определёнными строками и ячейками. Например, сотрудник  заполняет список товаров и их количество — итоговые суммы для товаров рассчитываются автоматически с помощью скрипта и добавляются в ячейки таблицы.

Такая настройка доступна в дизайнере интерфейсов, если вы вынесете переменную типа **Таблица** на шаблон формы. Эта переменная добавится на поле для моделирования с помощью виджета **Строка формы**. В настройках виджета отобразится вкладка **События Таблицы** со следующими опциями:

**(table-events-1.png)**

- **Событие при изменении ячейки** — срабатывает при каждом символе, введённом в ячейку, отслеживание которой вы настроили в скрипте. Доступно для колонок типа **Данные**, например **Строка**, **Число**, **Деньги** и т. д.;

- **Событие при окончании изменения ячейки** — случится после завершения редактирования ячейки, т. е. когда пользователь нажмёт **Enter** или переместит курсор за пределы ячейки. Доступно для колонок типа **Данные**;

- **Событие при удалении строки**;

- **Событие при перемещении строки**. 

Отслеживание этих событий реализуется в клиентских скриптах. В них доступна информация о затронутых данных таблицы: индекс строки, код колонки, предыдущее и новое значения ячейки при её изменении. Подробнее о структуре событий и работе с ними в скриптах читайте в [справке ELMA365 TS SDK](https://tssdk.elma365.com/ru/latest/modules/_02_types_.html#tablecellchangedoneevent).

Обратите внимание, в настройках виджета **Строка формы** есть также [вкладка События](form_line_widget.md#events). Для переменной типа **Таблица** на этой вкладке событие срабатывает при любом изменении данных. Здесь не доступно отслеживание изменений в определённых ячейках и строках. Оно настраивается только на вкладке **События Таблицы**.

## Пример добавления скрипта к событию таблицы

Рассмотрим на примере, как настроить запуск скрипта после изменения определённых данных в таблице.

Допустим, к товарам могут применяться следующие скидки:

- акционные — привязаны к определённому товару и хранятся в приложении **Товары**;

- персональные — привязаны к клиенту и хранятся в его карточке в приложении **Клиенты**.

При создании заказа сотрудник указывает клиента, а также выбирает товары и их количество в таблице **Состав заказа**. На основе этих данных с помощью скрипта в другие ячейки автоматически добавляются следующие значения: записывается цена, определяется применяемая скидка, рассчитывается стоимость с учётом скидки и итоговая сумма.

**(table-events-2.png)**

### Предварительные настройки

Рассмотрим настройки, которые выполняются до создания скрипта и его привязки к событию таблицы.

В разделе **Работа с клиентами** создайте три приложения:

1. **Клиенты**. Карточка клиента содержит поле **Персональная скидка, %** (`personalnaya\_skidka`) — свойство типа **Число**.

2. **Товары**. В карточке товара есть следующие поля:

	- **Цена** (`price`) — свойство типа **Деньги**;

	- **Есть скидка на товар** (`active\_discount`) — свойство типа **Выбор «да/нет»**;

	- **Скидка, %** (`discount`) — свойство типа **Число**;

	- **Цена со скидкой** (`discount\_price`) — свойство типа **Деньги**.

3. **Заказы**. В карточке заказа есть два поля:

	- **Клиент** (`client`) — свойство типа **Приложение**. В её настройках укажите приложение **Клиенты**, чтобы для расчёта стоимости заказанных товаров получать размер персональной скидки;

	- **Состав заказа** (`order`) — свойство типа **Таблица**.

Эта таблица состоит из следующих колонок типа **Данные**:

- **Позиция** (`item`) — свойство типа **Приложение**. В её настройках укажите приложение **Товары**, чтобы получать данные о наличии акционной скидки и суммы с учётом такой скидки. Заполняется пользователем вручную;

- **Цена за единицу без скидки** (`price`) — свойство типа **Деньги**. Отображает исходную стоимость позиции из её поля **Цена** (`price`);

- **Есть скидка на товар** (`on\_discount`) — свойство типа **Выбор «да/нет»**. Показывает, что при расчёте итоговой суммы применена акционная скидка из карточки товара;

- **Применена персональная скидка** (`personal\_discount\_applied`) — свойство типа **Выбор «да/нет»**. Показывает, что при расчёте итоговой суммы применена персональная скидка из карточки клиента;

- **Цена за единицу со скидкой** (`discount\_price`) — свойство типа **Деньги**. Отображает результат расчёта стоимости единицы товара с учётом применённой скидки;

- **Количество** (`amount`) — свойство типа **Число**. Пользователь указывает в этой ячейке таблицы количество заказываемых позиций. Это число учитывается в автоматическом расчёте итоговой суммы; 

- **Итог** (`total`) — свойство типа **Деньги**. Заполняется автоматически и отображает результат полученных в скрипте вычислений.

Используя данные из указанных приложений, можно настроить скрипт и автоматически заполнять ряд ячеек таблицы.

### Настроить скрипт и привязать его выполнение к событию таблицы

1. Перейдите в меню настроек приложения **Заказы**, выберите пункт **Настройка формы** и [откройте шаблон формы приложения в дизайнере интерфейсов](360029250931.md#edit_tab). 

2. На вкладке **Шаблон** перейдите в настройки контекстной переменной типа **Таблица**, нажав на значок шестерёнки.  
**(table-events-3.png)**

3. Чтобы после выбора клиента и заказанных позиций автоматически заполнялись суммы товаров, привяжите скрипт к событию таблицы. Для этого перейдите на вкладку **События Таблицы** и в поле **Событие при окончании изменения ячейки** создайте функцию `calculateTotal()`. В ней пропишите условия для выполнения скрипта:

	1. Заполнить поле **Клиент** (`client`).

	2. Указать значения в следующих ячейках таблицы **Состав заказа** (`order`):

	- **Позиция** (`item`) —  выбрать товары, которые заказал клиент;

	- **Количество** (`amount`) — добавить количество заказанных товаров.

После этого в скрипте автоматически проверяется наличие скидок и рассчитывается итоговая сумма для каждой выбранной позиции по следующему принципу:

- если у товара есть своя скидка — используется она;

- если нет — персональная скидка клиента.

Пример скрипта для автоматического расчёта итоговой суммы по товару

````
// Добавление функции, которая выполнится при окончании изменения ячеек таблицы   
async function calculateTotal(events: TableCellChangeDoneEvents<typeof Context.data.order>): Promise<void> \{  
// Проверка, что в карточке заказа заполнено поле Клиент    
    if (\!Context.data.client) \{  
        return  
    \}  
// Получение данных клиента из его карточки, включая персональную скидку      
const client = await Context.data.client.fetch()  
    for (let event of events) \{  
// Обработка данных при изменениях в колонке Позиция  
        if (event.rootColumnCode === 'item') \{  
            const row = Context.data.order\!\[event.rootRowIndex\] // получение строки, где указан товар  
            const item = await event.currentValue.fetch() // получение данных указанного товара из его карточки  
// Алгоритм автоматического заполнения таблицы, если у товара есть активная скидка  
            if (item.data.active\_discount) \{  
                row.discount\_price = item.data.discount\_price\!.multiply(row.amount ? row.amount : 1) // стоимость с учётом скидки   
                row.on\_discount = item.data.active\_discount // отметка, что применяется скидка из карточки товара  
                row.personal\_discount\_applied = false // персональная скидка клиента не используется  
                row.price = item.data.price\! // исходная стоимость позиции за единицу  
                row.total = row.discount\_price // общая сумма с учётом скидки  
            \} else \{  
// Алгоритм автоматического заполнения таблицы, если у товара нет активной скидки, т. е. применяется персональная скидка клиента  
                row.discount\_price = new Money((item.data.price\!.asFloat() - item.data.price\!.asFloat() \* (client.data.personalnaya\_skidka\! / 100)), 'RUB').multiply(row.amount ? row.amount : 1) // стоимость за единицу с учётом персональной скидки  
                row.on\_discount = item.data.active\_discount\! // получение данных о наличии скидки на товар  
                row.personal\_discount\_applied = true // отметка о применении персональной скидки  
                row.price = item.data.price\! // исходная стоимость позиции за единицу   
                row.total = row.discount\_price // общая сумма с учётом скидки  
            \}  
        \}  
// Обработка данных при изменениях в колонке Количество  
        if (event.rootColumnCode === 'amount') \{  
            const row = Context.data.order\!\[event.rootRowIndex\] // получение строки таблицы, где изменилось количество  
            if (row.item) \{ // проверка, что в строке выбран товар в колонке Позиция  
                row.total = row.discount\_price.multiply(event.currentValue) // пересчёт общей суммы по товару в колонке Итого  
            \}  
        \}  
    \}  
// Обновление данных таблицы для отображения изменений на форме  
    Context.data.order = Context.data.order  
\}
````

4. ````
Сохраните скрипт и опубликуйте форму приложения **Заказы**.

