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