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