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

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

Как перебрать таблицу формы в 1С

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

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

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

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

Какой тип таблицы на форме — определяем способ перебора

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

Табличная часть документаОсновной реквизит формы — объект

Перебор через Объект.ИмяТабличнойЧасти на сервере или через реквизит формы на клиенте

Таблица значений на формеРеквизит формы типа ТаблицаЗначений

На форме доступна как ДанныеФормыКоллекция, на сервере преобразуется в ТаблицаЗначений

Динамический списокОсновной реквизит — ДинамическийСписок

Прямой перебор невозможен, данные читаются запросом на сервере

Дерево значенийИерархическая структура

Перебор рекурсивно через ПолучитьЭлементы() на каждом уровне

Проверить тип просто: откройте редактор формы, найдите элемент таблицы в дереве элементов и посмотрите свойство «ПутьКДанным». Оно указывает на реквизит формы, тип которого виден в панели реквизитов.

Базовый перебор табличной части на клиенте

Самый частый случай — табличная часть документа (например, «Товары») на управляемой форме. В клиентской процедуре обращение идёт через Объект.ИмяТабличнойЧасти, и платформа сама предоставляет коллекцию данных формы.

&НаКлиенте

Процедура ПересчитатьСуммы(Команда)

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

Строка.Сумма = Строка.Количество * Строка.Цена;

КонецЦикла;

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

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

Обратный перебор (с конца) полезен при удалении строк по условию, чтобы индексы не «съезжали»:

&НаКлиенте

Процедура УдалитьПустыеСтроки(Команда)

Коллекция = Объект.Товары;

Индекс = Коллекция.Количество() - 1;

Пока Индекс >= 0 Цикл

Если Не ЗначениеЗаполнено(Коллекция[Индекс].Номенклатура) Тогда

Коллекция.Удалить(Индекс);

КонецЕсли;

Индекс = Индекс - 1;

КонецЦикла;

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

Перебор на сервере через РеквизитФормыВЗначение

Когда внутри цикла нужны запросы к базе, объектные методы или обращение к менеджерам объектов, перебор переносят в серверную процедуру. Здесь доступны два подхода.

Первый — продолжать работать с данными формы напрямую. Это быстрее, но тип ДанныеФормыКоллекция не поддерживает часть методов таблицы значений, например Итог() или Свернуть().

Второй — преобразовать реквизит в значение и работать с привычной табличной частью:

&НаСервере

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

ДокументОбъект = РеквизитФормыВЗначение("Объект");

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

// запросы, проверки, обращения к справочникам

КонецЦикла;

ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

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

Поиск строк по условию вместо полного перебора

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

&НаКлиенте

Процедура НайтиСтрокиПоНоменклатуре(Команда)

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

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

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

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

КонецЦикла;

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

Отбор работает только на равенство и только по реальным колонкам таблицы. Условия вида «больше», «содержит», «не заполнено» через НайтиСтроки не выразить — здесь остаётся классический цикл с проверкой.

Полный перебор или НайтиСтроки

Цикл Для Каждого

Подходит для любых условий, вычислений и модификации всех строк. Медленнее при поиске одной строки в большой таблице

НайтиСтроки(Отбор)

Быстрее при поиске по равенству одного или нескольких полей. Не поддерживает сравнения и сложные условия

Итог() / Свернуть()

Для агрегатов и группировок, но только на сервере после преобразования в таблицу значений

Перебор выделенных строк таблицы

Когда пользователь должен сам указать, с какими строками работать, перебирают не всю коллекцию, а выделенные строки элемента формы. Для этого используется свойство ВыделенныеСтроки — массив идентификаторов.

&НаКлиенте

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

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

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

Строка.Цена = Строка.Цена * 1.1;

КонецЦикла;

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

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

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

Перебор дерева значений на форме

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

&НаКлиенте

Процедура УстановитьПометки(ЭлементыДерева, Пометка)

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

Строка.Пометка = Пометка;

УстановитьПометки(Строка.ПолучитьЭлементы(), Пометка);

КонецЦикла;

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

&НаКлиенте

Процедура ПометитьВсе(Команда)

УстановитьПометки(Дерево.ПолучитьЭлементы(), Истина);

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

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

Производительность и типичные ошибки

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

Типичные ошибки при переборе
01
Запрос к базе внутри цикла на каждую строку — вместо этого один пакетный запрос по всей таблице и поиск результата в памяти
02
РеквизитФормыВЗначение() внутри цикла — многократное копирование данных формы, резкое падение скорости
03
Удаление строк в прямом цикле Для Каждого — пропуск строк после удаления
04
Сравнение с номером строки вместо идентификатора при работе с ВыделенныеСтроки — строка не находится
05
Попытка перебрать динамический список циклом — у него нет коллекции строк, данные читаются только запросом на сервере

Если внутри перебора нужно остатки, цены или другие данные из базы, правильный паттерн такой: выгрузить таблицу в запрос одним пакетом, получить результат и в цикле обращаться к нему через НайтиСтроки или индексированную структуру. Это сокращает число обращений к СУБД с количества строк до одного.

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

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

Значения в таблице на форме
Норма

Изменения видны сразу после выполнения процедуры

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

Данные изменились в объекте, но на форме старые — забыли ЗначениеВРеквизитФормы

Количество обработанных строк
Норма

Совпадает с ожидаемым по условию отбора

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

Часть строк пропущена — вероятно удаление в прямом цикле

Скорость выполнения
Норма

Таблица из тысячи строк обрабатывается без видимой паузы

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

Форма «зависает» — в цикле есть обращения к серверу или базе

Модифицированность формы
Норма

После изменений появился признак модифицированности

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

Изменения не фиксируются и могут быть потеряны при закрытии

FAQ

Как перебрать таблицу формы, если это динамический список?

Динамический список не хранит строки как коллекцию — это описание запроса. Для обхода данных выполните тот же запрос на сервере (через СхемуКомпоновкиДанных или вручную), получите таблицу значений и перебирайте её. Выделенные пользователем строки доступны через Элементы.Список.ВыделенныеСтроки как массив ссылок.

Чем отличается НомерСтроки от идентификатора строки?

НомерСтроки — видимый порядковый номер, он меняется при удалении и перемещении строк. Идентификатор (метод ПолучитьИдентификатор()) — внутреннее число, уникальное за время жизни формы. Для связи между клиентом и сервером и для ВыделенныеСтроки используется только идентификатор.

Как посчитать итог по колонке таблицы на форме?

На клиенте — циклом с накоплением суммы в переменную. На сервере таблицу значений можно свернуть методом Итог("ИмяКолонки"). Для табличных частей также доступен метод Итог() непосредственно у коллекции.

Можно ли прервать перебор досрочно?

Да, оператором Прервать — например, когда искомая строка найдена и дальнейший обход бессмыслен. Для пропуска текущей итерации используется Продолжить. Это простой способ ускорить поиск первой подходящей строки.

Почему изменения в цикле не видны на форме?

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

Как перебрать строки с учётом отбора, установленного пользователем в таблице?

Программного способа получить «только видимые после отбора» строки у коллекции данных формы нет. Нужно прочитать установленный отбор из настроек элемента формы и повторить ту же логику фильтрации в цикле вручную либо через НайтиСтроки с соответствующей структурой отбора.

Итог

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

Перебор таблицы формы делается циклом «Для Каждого» по коллекции данных формы; на сервере при необходимости используют РеквизитФормыВЗначение() один раз до цикла. Для поиска по равенству применяйте НайтиСтроки(), при удалении — обратный обход, для выделенных строк — НайтиПоИдентификатору(). Динамический список циклом не перебирается — только запросом.