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