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