К статье
Практический материал

Разработка и Конфигурация · 11 мин

1С управляемые формы: как передать таблицу значений с сервера на клиент

Как передать таблицу значений с сервера на клиент в управляемых формах 1С: ДанныеФормыКоллекция, ЗначениеВДанныеФормы, хранилище значений, JSON и типичные ошибки.

В управляемых формах 1С тип «ТаблицаЗначений» не сериализуется напрямую между сервером и клиентом: попытка вернуть его из серверной процедуры с директивой &НаКлиенте-вызова приведёт к ошибке преобразования данных. Это ограничение платформы, а не ошибка в коде — таблица значений относится к типам, доступным только на сервере, наряду с запросами, построителями отчётов и объектами СУБД.

Рабочих способов передать данные несколько: преобразование таблицы в реквизит формы типа «ТаблицаЗначений» через ЗначениеВДанныеФормы(), упаковка во временное хранилище, сериализация в JSON или передача массива структур. Выбор зависит от объёма данных, необходимости отображения в форме и дальнейшей обработки на клиенте.

Ниже разобраны все рабочие варианты с готовым кодом, ограничения каждого подхода и типичные ошибки, из-за которых данные «теряются» между вызовами.

Почему таблицу значений нельзя вернуть напрямую

Клиент-серверное взаимодействие в управляемых формах построено на сериализации: при вызове серверной процедуры параметры и возвращаемые значения упаковываются во внутренний формат платформы. Тип «ТаблицаЗначений» в этот формат не сериализуется — это серверный объект, привязанный к контексту сервера приложений.

При попытке вернуть таблицу из функции &НаСервере в клиентский контекст возникает ошибка вида «Ошибка отображения типов» или «Переданное значение не может быть преобразовано». То же относится к дереву значений, результату запроса и объекту «СхемаКомпоновкиДанных».

Важно понимать: реквизит формы типа «ТаблицаЗначений» — это не то же самое, что программный объект «ТаблицаЗначений». Внутри формы он представлен типом «ДанныеФормыКоллекция», который платформа умеет передавать между клиентом и сервером автоматически. На этом и строится основной способ.

Способ 1. Реквизит формы и ЗначениеВДанныеФормы

Штатный и самый надёжный вариант — объявить в форме реквизит с типом «ТаблицаЗначений», добавить в него нужные колонки, а на сервере заполнить его из обычной таблицы значений. После завершения серверного вызова данные окажутся на клиенте без дополнительных действий.

&НаСервере

Процедура ЗаполнитьТаблицуНаСервере()

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Номенклатура");

ТЗ.Колонки.Добавить("Количество");

// ... заполнение ТЗ данными ...

ЗначениеВДанныеФормы(ТЗ, РеквизитТаблица);

КонецПроцедуры

&НаКлиенте

Процедура Заполнить(Команда)

ЗаполнитьТаблицуНаСервере();

// РеквизитТаблица уже содержит данные на клиенте

Для Каждого Строка Из РеквизитТаблица Цикл

Сообщить(Строка.Номенклатура);

КонецЦикла;

КонецПроцедуры

Если колонки реквизита должны формироваться динамически, их добавляют через ИзменитьРеквизиты() в серверном контексте: сначала формируется массив добавляемых реквизитов типа «РеквизитФормы», затем вызывается метод изменения структуры формы.

Обратный перенос — из реквизита формы в объектную таблицу — выполняется методом РеквизитФормыВЗначение("ИмяРеквизита") на сервере. Это нужно, когда требуется обработать данные запросом или передать в объектный модуль.

Порядок действий
  1. 1
    Добавьте в форму реквизит типа «ТаблицаЗначений» и опишите его колонки (в конфигураторе или через ИзменитьРеквизиты).
  2. 2
    В серверной процедуре сформируйте обычную ТаблицуЗначений и заполните её данными.
  3. 3
    Вызовите ЗначениеВДанныеФормы(ТЗ, ИмяРеквизита).
  4. 4
    В клиентском коде обращайтесь к реквизиту как к коллекции: обход циклом, поиск, итоги.

Способ 2. Временное хранилище

Когда данные нужны не для отображения в форме, а для передачи между формами или длительного хранения, таблицу помещают во временное хранилище. Метод ПоместитьВоВременноеХранилище() возвращает адрес — строку, которую можно свободно передавать между клиентом и сервером.

&НаСервере

Функция ПолучитьАдресТаблицы()

ТЗ = СформироватьТаблицу();

Возврат ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);

КонецФункции

Второй параметр — УникальныйИдентификатор формы — критически важен: он привязывает данные к времени жизни формы. Без него хранилище очистится после завершения серверного вызова, и по адресу окажется пусто. Это одна из самых частых причин «пропадающих» данных.

Извлечение выполняется на сервере: ТЗ = ПолучитьИзВременногоХранилища(Адрес). На клиенте содержимое хранилища недоступно — адрес используется только как «ключ», который передаётся в другую форму через параметры или в следующий серверный вызов.

Способ 3. JSON и массив структур

Если таблица небольшая и нужна именно на клиенте как данные (а не как реквизит формы), её можно сериализовать в JSON-строку. На сервере таблица обходится циклом, каждая строка превращается в структуру, структуры складываются в массив, массив записывается через ЗаписьJSON. На клиенте строка читается через ПрочитатьJSON — результатом будет массив структур.

Более простой частный случай — вернуть из серверной функции сразу массив структур. Структуры и массивы сериализуются платформой, поэтому такой вариант работает без JSON. Ограничение: имена ключей структуры должны быть корректными идентификаторами, а вложенные значения — сериализуемыми типами.

Оба варианта подходят для передачи справочных данных в веб-клиенте и тонком клиенте, когда тянуть весь механизм реквизитов формы избыточно. Для таблиц в десятки тысяч строк JSON-сериализация заметно уступает по скорости передаче через реквизит формы.

Сравнение вариантов

Реквизит формы + ЗначениеВДанныеФормы

Когда данные отображаются в таблице формы или редактируются пользователем. Ограничение: структуру колонок нужно описывать заранее или менять через ИзменитьРеквизиты.

Временное хранилище

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

JSON / массив структур

Когда нужны небольшие данные для клиентской логики или обмена с внешними сервисами. Ограничение: ручная сериализация, потеря типов (даты и ссылки требуют отдельной обработки).

Передача таблицы в другую форму

Типовой сценарий — подбор: в основной форме открывается форма подбора, пользователь выбирает строки, и выбранная таблица должна вернуться в форму-владельца. Здесь таблица значений передаётся через параметры открытия или через хранилище.

Рекомендуемый шаблон: в форме подбора при закрытии таблица помещается во временное хранилище с привязкой к идентификатору формы-владельца, а адрес возвращается через Закрыть(Адрес) или оповещение о выборе. Форма-владелец в обработчике получает адрес и извлекает таблицу на сервере.

Передавать сам реквизит формы между формами нельзя — ДанныеФормыКоллекция существует только внутри своей формы. Для передачи между формами всегда нужен промежуточный формат: хранилище, массив структур или строка JSON.

Типичные ошибки и как их проверить

Первая группа ошибок связана с директивами компиляции. Процедура, помеченная &НаСервереБезКонтекста, не имеет доступа к данным формы — ЗначениеВДанныеФормы там недоступен. Для работы с реквизитами формы нужна директива &НаСервере.

Вторая группа — несовпадение колонок. ЗначениеВДанныеФормы требует, чтобы состав колонок исходной таблицы соответствовал реквизиту формы; лишние колонки в ТЗ вызовут ошибку, а отсутствующие останутся пустыми. Перед заполнением полезно явно приводить таблицу к нужному составу.

Третья — потеря данных во временном хранилище из-за отсутствия привязки к форме или из-за того, что форма-владелец уже закрыта к моменту чтения. Проверка проста: сразу после ПоместитьВоВременноеХранилище выполните ПолучитьИзВременногоХранилища в том же вызове и убедитесь, что тип результата — «ТаблицаЗначений».

Типичные ошибки
01
Возврат ТаблицаЗначений из серверной функции на клиент — ошибка сериализации; используйте реквизит формы или хранилище.
02
ПоместитьВоВременноеХранилище без второго параметра — данные удаляются после вызова; передавайте УникальныйИдентификатор формы.
03
Вызов ЗначениеВДанныеФормы в процедуре &НаСервереБезКонтекста — метод недоступен; смените директиву на &НаСервере.
04
Несовпадение колонок ТЗ и реквизита формы — ошибка заполнения; приводите состав колонок заранее.

Производительность и объёмы данных

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

Практические меры: заполняйте таблицу одним серверным вызовом вместо цикла вызовов; не делайте лишних серверных обращений, пока большая таблица открыта на редактирование; для больших списков рассмотрите динамический список вместо таблицы значений — он читает данные порциями.

Для контроля объёма полезно замерять количество строк и длительность вызова через ТекущаяУниверсальнаяДатаВМиллисекундах() на этапе разработки: если заполнение таблицы занимает секунды, проблема обычно в запросе, а не в механизме передачи.

Контрольные точки

Как проверить результат

Данные на клиенте после серверного вызова
Норма

Реквизит формы содержит строки, таблица на форме отображает значения

Тревожный признак

Реквизит пуст или ошибка преобразования типов

Адрес временного хранилища
Норма

ПолучитьИзВременногоХранилища возвращает ТаблицаЗначений

Тревожный признак

Возвращается Неопределено — нет привязки к форме или хранилище очищено

Состав колонок
Норма

Колонки ТЗ совпадают с колонками реквизита формы

Тревожный признак

Ошибка при ЗначениеВДанныеФормы или пустые колонки

Частые вопросы

Можно ли передать таблицу значений как параметр при открытии формы?

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

Чем ЗначениеВДанныеФормы отличается от РеквизитФормыВЗначение?

Первый метод переносит объектное значение (таблицу) в реквизит формы, второй — наоборот, извлекает реквизит формы в объектное значение для серверной обработки. В паре они покрывают обмен в обе стороны.

Почему после серверного вызова таблица на форме пустая?

Чаще всего процедура объявлена как &НаСервереБезКонтекста и не видит реквизит, либо заполняется локальная переменная вместо реквизита формы. Проверьте директиву и что заполнение идёт именно через ЗначениеВДанныеФормы в реквизит.

Как передать дерево значений?

Аналогично: создайте реквизит формы типа «ДеревоЗначений» и заполните его через ЗначениеВДанныеФормы. Для передачи между формами дерево также придётся конвертировать — напрямую оно не сериализуется.

Что быстрее: JSON или реквизит формы?

Для отображения в форме быстрее и проще реквизит — платформа передаёт его оптимизированно. JSON оправдан для обмена с внешними системами и небольших объёмов, где важна простота формата.

Итог

Что важно запомнить

ТаблицаЗначений не передаётся между сервером и клиентом напрямую. Для отображения используйте реквизит формы и ЗначениеВДанныеФормы, для передачи между формами — временное хранилище с привязкой к УникальныйИдентификатор, для небольших данных — массив структур или JSON. Следите за директивами компиляции и совпадением колонок.