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

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

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

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

Табличная часть на форме — это не сама таблица данных, а её визуальное представление. Когда разработчик пытается «прочитать» табличную часть, он на самом деле обращается либо к данным формы (коллекции строк в памяти), либо к элементу формы «Таблица», который хранит информацию о выделении и видимости. Путаница между этими двумя уровнями — главный источник ошибок у начинающих разработчиков 1С.

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

Ниже разобраны основные сценарии: обход строк на клиенте и сервере, получение выделенных строк, выгрузка в таблицу значений, работа с обычными формами и типичные ошибки при передаче данных между клиентом и сервером.

Где физически хранятся данные табличной части

В управляемой форме табличная часть документа или справочника существует в двух ипостасях. Первая — реквизит объекта, например Объект.Товары, который после открытия формы преобразуется в ДанныеФормыКоллекция. Вторая — элемент формы «Таблица» (например, Элементы.Товары), который отвечает только за отображение: текущую строку, выделение, сортировку, видимость колонок.

Для чтения значений ячеек всегда обращайтесь к данным, а не к элементу формы. Конструкция Элементы.Товары.ТекущиеДанные вернёт строку текущей записи, но попытка перебрать Элементы.Товары циклом не даст результата — элемент формы не является коллекцией строк.

Обход всех строк табличной части на клиенте

Самый простой сценарий — перебрать все строки и прочитать значения реквизитов. На клиенте это делается циклом «Для Каждого» по коллекции данных формы:

&НаКлиенте

Процедура ПоказатьСуммы(Команда)

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Сообщить("Номенклатура: " + СтрокаТовара.Номенклатура

+ ", сумма: " + СтрокаТовара.Сумма);

КонецЦикла;

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

Если табличная часть отображается динамическим списком или данные привязаны к реквизиту формы, а не к объекту, путь будет другим — через имя реквизита формы: Для Каждого Строка Из ЭтаФорма.МояТаблица Цикл. Имя берётся из свойств реквизита формы в конфигураторе, а не из имени элемента формы.

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

Получение текущей и выделенных строк

Когда нужна только строка, на которой стоит курсор, используйте свойство ТекущиеДанные элемента формы:

&НаКлиенте

Процедура ОбработатьТекущую(Команда)

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

Возврат; // строка не выбрана

КонецЕсли;

СуммаСтроки = ТекущиеДанные.Сумма;

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

Обязательно проверяйте результат на Неопределено: если таблица пуста или фокус не в ней, свойство вернёт именно это значение, и обращение к реквизиту вызовет ошибку «Поле объекта не обнаружено».

Выделенные пользователем строки

Свойство Элементы.Товары.ВыделенныеСтроки возвращает массив идентификаторов строк, а не сами строки. Чтобы получить данные, каждый идентификатор нужно разрешить через НайтиПоИдентификатору:

&НаКлиенте

Процедура ОбработатьВыделенные(Команда)

Для Каждого Идентификатор Из Элементы.Товары.ВыделенныеСтроки Цикл

СтрокаТовара = Объект.Товары.НайтиПоИдентификатору(Идентификатор);

Если СтрокаТовара <> Неопределено Тогда

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

КонецЕсли;

КонецЦикла;

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

Типичные ошибки
01
Обход Элементы.Товары циклом вместо Объект.Товары — элемент формы не содержит строк, код завершится ошибкой
02
Использование ВыделенныеСтроки как готовых строк — там лежат только идентификаторы, нужен НайтиПоИдентификатору
03
Отсутствие проверки ТекущиеДанные на Неопределено — падение при пустой таблице

Получение данных на сервере и выгрузка в таблицу значений

На сервере управляемой формы коллекция ДанныеФормыКоллекция доступна так же, но у неё есть ограничение: её нельзя напрямую передать в запрос или сохранить в хранилище значений. Для этого коллекцию выгружают в таблицу значений методом Выгрузить():

&НаСервере

Процедура ОбработатьНаСервере()

ТаблицаТоваров = Объект.Товары.Выгрузить();

// Теперь ТаблицаТоваров — обычная таблица значений

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ ИЗ &Таблица КАК Таблица";

Запрос.УстановитьПараметр("Таблица", ТаблицаТоваров);

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

Метод Выгрузить() без параметров скопирует все колонки. Если нужны только часть колонок или отобранные строки, передайте параметры: Выгрузить(МассивСтрок, "Номенклатура,Количество"). Это удобно, когда на сервер уходят только выделенные строки.

Передача данных с клиента на сервер

Коллекцию данных формы нельзя передать параметром в серверную процедуру с контекстом формы, если процедура объявлена как &НаСервереБезКонтекста. Рабочие варианты: вызвать серверную процедуру с контекстом формы (&НаСервере) и там обратиться к Объект.Товары, либо на клиенте собрать массив структур с нужными полями и передать его в процедуру без контекста.

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

&НаСервере + Объект.Товары

Простой доступ ко всей коллекции, но вызов тянет контекст формы — тяжелее и медленнее

Массив структур в &НаСервереБезКонтекста

Лёгкий вызов и контроль передаваемых данных, но нужно вручную собирать структуры на клиенте

Выгрузить() в таблицу значений

Подходит для запросов и массовой обработки, но создаёт копию — изменения не вернутся в форму автоматически

Работа в обычных формах (обычное приложение)

В обычном приложении разделения на клиент и сервер внутри формы нет, и табличная часть объекта доступна напрямую как табличная часть — с методами Выгрузить(), Найти(), Итог(). Обход выполняется тем же циклом Для Каждого Строка Из Объект.Товары Цикл.

Элемент формы «ТабличноеПоле» здесь также имеет свойство ТекущиеДанные и коллекцию ВыделенныеСтроки, но в обычных формах ВыделенныеСтроки — это уже коллекция самих строк, а не идентификаторов, поэтому НайтиПоИдентификатору не требуется:

Для Каждого СтрокаТовара Из ЭлементыФормы.Товары.ВыделенныеСтроки Цикл

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

КонецЦикла;

Поиск конкретной строки и итоги по табличной части

Если нужна не вся табличная часть, а строки с определённым условием, используйте НайтиСтроки — он возвращает массив подходящих строк:

Отбор = Новый Структура("Номенклатура", ИскомаяНоменклатура);

НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Для Каждого СтрокаТовара Из НайденныеСтроки Цикл

СтрокаТовара.Цена = НоваяЦена;

КонецЦикла;

Для подсчёта суммы по колонке без цикла применяйте метод Итог("Сумма") — он работает и на клиенте, и на сервере и не требует выгрузки в таблицу значений. Это быстрее и короче, чем ручное накопление в цикле.

Порядок действий при чтении табличной части
  1. 1
    Определите, где выполняется код: клиент или сервер, управляемая или обычная форма
  2. 2
    Найдите путь к коллекции данных: Объект.Товары или реквизит формы
  3. 3
    Выберите способ: полный обход циклом, НайтиСтроки по отбору или ВыделенныеСтроки для выбранных
  4. 4
    Если данные нужны в запросе или без контекста формы — выгрузите в таблицу значений
  5. 5
    Проверьте результат на пустую коллекцию и Неопределено перед обращением к полям

Проверка результата и ограничения

После чтения данных убедитесь, что коллекция не пуста: Объект.Товары.Количество() = 0 — признак того, что обход не выполнится и последующая логика должна это учитывать. При работе с идентификаторами выделенных строк проверяйте результат НайтиПоИдентификатору на Неопределено — строка могла быть удалена между выделением и обработкой.

Помните об ограничении тонкого клиента: на нём недоступны некоторые операции с таблицами значений, а вызовы сервера стоят дороже. Если обработка массивная (запросы, расчёты), переносите её на сервер и передавайте только необходимые данные, а не всю форму.

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

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

Количество строк
Норма

Объект.Товары.Количество() больше нуля, цикл отрабатывает

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

Ноль строк — проверьте, тот ли это реквизит и заполнен ли документ

ТекущиеДанные
Норма

Возвращает строку с доступными полями

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

Неопределено — таблица пуста или фокус не в таблице

Выгрузка в ТЗ
Норма

Выгрузить() вернул таблицу с колонками табличной части

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

Пустая таблица при заполненной форме — выгружали не ту коллекцию

Итог

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

Читайте данные через коллекцию данных формы (Объект.Товары), а не через элемент формы. Для выделенных строк используйте ВыделенныеСтроки + НайтиПоИдентификатору. Для запросов и сервера без контекста выгружайте коллекцию в таблицу значений методом Выгрузить(). Всегда проверяйте ТекущиеДанные и результат поиска на Неопределено.

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

Почему цикл по Элементы.Товары выдаёт ошибку?

Элемент формы «Таблица» — это элемент управления, а не коллекция данных. Перебирать нужно коллекцию данных: Объект.Товары или реквизит формы, к которому привязана таблица.

Как получить номер текущей строки табличной части?

Через Элементы.Товары.ТекущиеДанные.НомерСтроки после проверки, что ТекущиеДанные не равны Неопределено. Либо возьмите идентификатор: Элементы.Товары.ТекущаяСтрока — и найдите строку по нему.

Можно ли передать табличную часть в процедуру &НаСервереБезКонтекста?

Напрямую ДанныеФормыКоллекция передать нельзя. Соберите на клиенте массив структур с нужными полями либо выполните обработку в серверной процедуре с контекстом формы, где доступен Объект.Товары.

Как скопировать строки из одной табличной части в другую?

Обойдите исходную коллекцию циклом и для каждой строки вызовите НоваяСтрока = Объект.Приёмник.Добавить(), затем заполните поля через ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточник) при совпадающих именах колонок.

Чем НайтиСтроки отличается от обхода с условием внутри цикла?

НайтиСтроки возвращает массив строк по структуре отбора и работает быстрее и короче для простых условий «равно». Если условие сложное (сравнения, вычисления), используйте обычный цикл с проверкой внутри.

Почему после Выгрузить() изменения в таблице значений не видны на форме?

Метод Выгрузить() создаёт независимую копию данных. Чтобы вернуть изменения в форму, загрузите таблицу обратно: Объект.Товары.Загрузить(ТаблицаТоваров) — при этом текущее содержимое табличной части будет заменено полностью.