Разработка и Конфигурация · 11 мин
1С управляемые формы: как передать таблицу значений с сервера на клиент
Как передать таблицу значений с сервера на клиент в управляемых формах 1С: ДанныеФормыКоллекция, ЗначениеВДанныеФормы, хранилище значений, JSON и типичные ошибки.
В управляемых формах 1С тип «ТаблицаЗначений» не сериализуется напрямую между сервером и клиентом: попытка вернуть его из серверной процедуры с директивой &НаКлиенте-вызова приведёт к ошибке преобразования данных. Это ограничение платформы, а не ошибка в коде — таблица значений относится к типам, доступным только на сервере, наряду с запросами, построителями отчётов и объектами СУБД.
Рабочих способов передать данные несколько: преобразование таблицы в реквизит формы типа «ТаблицаЗначений» через ЗначениеВДанныеФормы(), упаковка во временное хранилище, сериализация в JSON или передача массива структур. Выбор зависит от объёма данных, необходимости отображения в форме и дальнейшей обработки на клиенте.
Ниже разобраны все рабочие варианты с готовым кодом, ограничения каждого подхода и типичные ошибки, из-за которых данные «теряются» между вызовами.
Почему таблицу значений нельзя вернуть напрямую
Клиент-серверное взаимодействие в управляемых формах построено на сериализации: при вызове серверной процедуры параметры и возвращаемые значения упаковываются во внутренний формат платформы. Тип «ТаблицаЗначений» в этот формат не сериализуется — это серверный объект, привязанный к контексту сервера приложений.
При попытке вернуть таблицу из функции &НаСервере в клиентский контекст возникает ошибка вида «Ошибка отображения типов» или «Переданное значение не может быть преобразовано». То же относится к дереву значений, результату запроса и объекту «СхемаКомпоновкиДанных».
Важно понимать: реквизит формы типа «ТаблицаЗначений» — это не то же самое, что программный объект «ТаблицаЗначений». Внутри формы он представлен типом «ДанныеФормыКоллекция», который платформа умеет передавать между клиентом и сервером автоматически. На этом и строится основной способ.
Способ 1. Реквизит формы и ЗначениеВДанныеФормы
Штатный и самый надёжный вариант — объявить в форме реквизит с типом «ТаблицаЗначений», добавить в него нужные колонки, а на сервере заполнить его из обычной таблицы значений. После завершения серверного вызова данные окажутся на клиенте без дополнительных действий.
&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура");
ТЗ.Колонки.Добавить("Количество");
// ... заполнение ТЗ данными ...
ЗначениеВДанныеФормы(ТЗ, РеквизитТаблица);
КонецПроцедуры
&НаКлиенте
Процедура Заполнить(Команда)
ЗаполнитьТаблицуНаСервере();
// РеквизитТаблица уже содержит данные на клиенте
Для Каждого Строка Из РеквизитТаблица Цикл
Сообщить(Строка.Номенклатура);
КонецЦикла;
КонецПроцедуры
Если колонки реквизита должны формироваться динамически, их добавляют через ИзменитьРеквизиты() в серверном контексте: сначала формируется массив добавляемых реквизитов типа «РеквизитФормы», затем вызывается метод изменения структуры формы.
Обратный перенос — из реквизита формы в объектную таблицу — выполняется методом РеквизитФормыВЗначение("ИмяРеквизита") на сервере. Это нужно, когда требуется обработать данные запросом или передать в объектный модуль.
- 1Добавьте в форму реквизит типа «ТаблицаЗначений» и опишите его колонки (в конфигураторе или через ИзменитьРеквизиты).
- 2В серверной процедуре сформируйте обычную ТаблицуЗначений и заполните её данными.
- 3Вызовите ЗначениеВДанныеФормы(ТЗ, ИмяРеквизита).
- 4В клиентском коде обращайтесь к реквизиту как к коллекции: обход циклом, поиск, итоги.
Способ 2. Временное хранилище
Когда данные нужны не для отображения в форме, а для передачи между формами или длительного хранения, таблицу помещают во временное хранилище. Метод ПоместитьВоВременноеХранилище() возвращает адрес — строку, которую можно свободно передавать между клиентом и сервером.
&НаСервере
Функция ПолучитьАдресТаблицы()
ТЗ = СформироватьТаблицу();
Возврат ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);
КонецФункции
Второй параметр — УникальныйИдентификатор формы — критически важен: он привязывает данные к времени жизни формы. Без него хранилище очистится после завершения серверного вызова, и по адресу окажется пусто. Это одна из самых частых причин «пропадающих» данных.
Извлечение выполняется на сервере: ТЗ = ПолучитьИзВременногоХранилища(Адрес). На клиенте содержимое хранилища недоступно — адрес используется только как «ключ», который передаётся в другую форму через параметры или в следующий серверный вызов.
Способ 3. JSON и массив структур
Если таблица небольшая и нужна именно на клиенте как данные (а не как реквизит формы), её можно сериализовать в JSON-строку. На сервере таблица обходится циклом, каждая строка превращается в структуру, структуры складываются в массив, массив записывается через ЗаписьJSON. На клиенте строка читается через ПрочитатьJSON — результатом будет массив структур.
Более простой частный случай — вернуть из серверной функции сразу массив структур. Структуры и массивы сериализуются платформой, поэтому такой вариант работает без JSON. Ограничение: имена ключей структуры должны быть корректными идентификаторами, а вложенные значения — сериализуемыми типами.
Оба варианта подходят для передачи справочных данных в веб-клиенте и тонком клиенте, когда тянуть весь механизм реквизитов формы избыточно. Для таблиц в десятки тысяч строк JSON-сериализация заметно уступает по скорости передаче через реквизит формы.
Сравнение вариантов
Когда данные отображаются в таблице формы или редактируются пользователем. Ограничение: структуру колонок нужно описывать заранее или менять через ИзменитьРеквизиты.
Когда таблицу нужно передать в другую форму или сохранить между вызовами. Ограничение: на клиенте доступен только адрес, извлечение — только на сервере.
Когда нужны небольшие данные для клиентской логики или обмена с внешними сервисами. Ограничение: ручная сериализация, потеря типов (даты и ссылки требуют отдельной обработки).
Передача таблицы в другую форму
Типовой сценарий — подбор: в основной форме открывается форма подбора, пользователь выбирает строки, и выбранная таблица должна вернуться в форму-владельца. Здесь таблица значений передаётся через параметры открытия или через хранилище.
Рекомендуемый шаблон: в форме подбора при закрытии таблица помещается во временное хранилище с привязкой к идентификатору формы-владельца, а адрес возвращается через Закрыть(Адрес) или оповещение о выборе. Форма-владелец в обработчике получает адрес и извлекает таблицу на сервере.
Передавать сам реквизит формы между формами нельзя — ДанныеФормыКоллекция существует только внутри своей формы. Для передачи между формами всегда нужен промежуточный формат: хранилище, массив структур или строка JSON.
Типичные ошибки и как их проверить
Первая группа ошибок связана с директивами компиляции. Процедура, помеченная &НаСервереБезКонтекста, не имеет доступа к данным формы — ЗначениеВДанныеФормы там недоступен. Для работы с реквизитами формы нужна директива &НаСервере.
Вторая группа — несовпадение колонок. ЗначениеВДанныеФормы требует, чтобы состав колонок исходной таблицы соответствовал реквизиту формы; лишние колонки в ТЗ вызовут ошибку, а отсутствующие останутся пустыми. Перед заполнением полезно явно приводить таблицу к нужному составу.
Третья — потеря данных во временном хранилище из-за отсутствия привязки к форме или из-за того, что форма-владелец уже закрыта к моменту чтения. Проверка проста: сразу после ПоместитьВоВременноеХранилище выполните ПолучитьИзВременногоХранилища в том же вызове и убедитесь, что тип результата — «ТаблицаЗначений».
Производительность и объёмы данных
Каждый серверный вызов в управляемой форме переносит изменённые данные формы между клиентом и сервером. Если реквизит-таблица содержит тысячи строк, каждый вызов &НаСервере будет тащить её туда и обратно, что заметно замедляет работу в тонком и веб-клиенте.
Практические меры: заполняйте таблицу одним серверным вызовом вместо цикла вызовов; не делайте лишних серверных обращений, пока большая таблица открыта на редактирование; для больших списков рассмотрите динамический список вместо таблицы значений — он читает данные порциями.
Для контроля объёма полезно замерять количество строк и длительность вызова через ТекущаяУниверсальнаяДатаВМиллисекундах() на этапе разработки: если заполнение таблицы занимает секунды, проблема обычно в запросе, а не в механизме передачи.
Как проверить результат
Реквизит формы содержит строки, таблица на форме отображает значения
Реквизит пуст или ошибка преобразования типов
ПолучитьИзВременногоХранилища возвращает ТаблицаЗначений
Возвращается Неопределено — нет привязки к форме или хранилище очищено
Колонки ТЗ совпадают с колонками реквизита формы
Ошибка при ЗначениеВДанныеФормы или пустые колонки
Частые вопросы
Можно ли передать таблицу значений как параметр при открытии формы?
Напрямую — нет, по той же причине сериализации. Поместите таблицу во временное хранилище в форме-источнике и передайте адрес через структуру параметров ОткрытьФорму(), либо передайте массив структур, если данных немного.
Чем ЗначениеВДанныеФормы отличается от РеквизитФормыВЗначение?
Первый метод переносит объектное значение (таблицу) в реквизит формы, второй — наоборот, извлекает реквизит формы в объектное значение для серверной обработки. В паре они покрывают обмен в обе стороны.
Почему после серверного вызова таблица на форме пустая?
Чаще всего процедура объявлена как &НаСервереБезКонтекста и не видит реквизит, либо заполняется локальная переменная вместо реквизита формы. Проверьте директиву и что заполнение идёт именно через ЗначениеВДанныеФормы в реквизит.
Как передать дерево значений?
Аналогично: создайте реквизит формы типа «ДеревоЗначений» и заполните его через ЗначениеВДанныеФормы. Для передачи между формами дерево также придётся конвертировать — напрямую оно не сериализуется.
Что быстрее: JSON или реквизит формы?
Для отображения в форме быстрее и проще реквизит — платформа передаёт его оптимизированно. JSON оправдан для обмена с внешними системами и небольших объёмов, где важна простота формата.
Что важно запомнить
ТаблицаЗначений не передаётся между сервером и клиентом напрямую. Для отображения используйте реквизит формы и ЗначениеВДанныеФормы, для передачи между формами — временное хранилище с привязкой к УникальныйИдентификатор, для небольших данных — массив структур или JSON. Следите за директивами компиляции и совпадением колонок.