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