Как обойти табличную часть на клиенте в управляемой форме 1С 8.3 до записи документа?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Когда мы работаем с управляемыми формами в 1С:Предприятии 8.3, часто возникает задача обработки данных табличной части документа, который еще не записан — для этого подойдёт универсальная обработка табличных частей для управляемых форм. Эти данные в данный момент находятся исключительно на клиенте. Возникает вопрос: как правильно организовать цикл по строкам такой табличной части, чтобы получить доступ к значениям реквизитов каждой строки?

Рассмотрим эту проблему подробнее, проанализируем распространенные ошибки и предложим эффективные решения.

Распространенная ошибка: попытка обхода элемента управления формы

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


Для Каждого Элемент Из Элементы.ТабличнаяЧасть Цикл
    // Что-то делаем со строкой
КонецЦикла;

Однако при попытке выполнения такого кода мы сталкиваемся с ошибкой "Итератор не задан" — быстро проверить и отладить алгоритм поможет интерактивная консоль кода с отладчиком для 1С:Предприятия. Почему это происходит? Потому что Элементы.ТабличнаяЧасть — это не коллекция данных, а элемент управления формы (например, табличное поле), который отвечает за визуальное отображение. Он не предоставляет прямого итератора для обхода своих строк как коллекции данных.

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

Правильный подход: обход коллекции данных формы

Чтобы обойти табличную часть на клиенте до записи документа, мы должны обращаться к данным формы, которые представляют собой "слепок" объекта. Для этого используется основной реквизит формы Объект и имя нужной нам табличной части.

Рассмотрим по шагам, как это сделать:

  1. Определяем основной реквизит формы: В управляемой форме, как правило, существует основной реквизит, который связан с прикладным объектом (например, документом). Этот реквизит обычно называется Объект и имеет тип ДокументОбъект.<ИмяДокумента>, но на клиенте он представлен как ДанныеФормыСтруктура.
  2. Находим имя табличной части: В конфигураторе, в дереве реквизитов формы, мы видим структуру нашего Объекта. Под ним будут располагаться наши табличные части. Их имена нам и понадобятся. Например, если у вас табличная часть называется "Товары", то путь к ней будет Объект.Товары.
  3. Используем цикл Для Каждого...Из...Цикл: Мы итерируем по коллекции данных табличной части, которая доступна через основной реквизит формы.

Вот пример кода, который демонстрирует правильный способ обхода табличной части:


// Предположим, что у нашей формы есть основной реквизит 'Объект',
// связанный с документом, и в нем есть табличная часть с именем 'ИмяТабличнойЧасти'.

Для Каждого СтрокаТЧ Из Объект.ИмяТабличнойЧасти Цикл
    // Здесь 'СтрокаТЧ' - это объект типа ДанныеФормыЭлементКоллекции,
    // который представляет собой одну строку табличной части.

    // Мы можем обращаться к реквизитам этой строки через точку:
    // Например, если в табличной части есть реквизит 'Номенклатура' и 'Количество':
    Сообщить("Номенклатура: " + СтрокаТЧ.Номенклатура + ", Количество: " + СтрокаТЧ.Количество);

    // Можно также изменять значения реквизитов строки:
    // СтрокаТЧ.Флаг = Истина;
    // СтрокаТЧ.Цена = СтрокаТЧ.Цена * 1.1; // Увеличим цену на 10%
КонецЦикла;

В этом примере СтрокаТЧ является переменной цикла, которая на каждой итерации содержит объект типа ДанныеФормыЭлементКоллекции. Этот объект позволяет нам получать и устанавливать значения реквизитов текущей строки табличной части. При необходимости динамически расширить состав доступных полей на форме можно использовать метод программного создания колонок в табличной части с сохранением их значений в документе.

Важный момент: Как нам пояснили в обсуждении, необходимо точно знать имена основного реквизита (обычно Объект) и самой табличной части. Эти имена берутся из дерева реквизитов формы в конфигураторе. Например, если вы видите реквизит формы Объект, а внутри него есть коллекция Загрузки, то правильный путь будет Объект.Загрузки.

Альтернативный метод: обход по индексу с использованием ДанныеСтроки()

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


// Предположим, что элемент формы, отображающий табличную часть, имеет имя 'Загрузки'.
// Имя 'Загрузки' здесь - это имя элемента формы, а не самой коллекции данных.

Колво = Объект.Загрузки.Количество - 1; // Общее количество строк, с учетом индексации с 0
СчЦикла = 0;
Для СчЦикла = 0 По Колво Цикл
    // Получаем данные строки по индексу
    ДанныеТекущейСтроки = Элементы.Загрузки.ДанныеСтроки(СчЦикла);

    // Теперь мы можем работать с реквизитами этой строки:
    // Например, если у строки есть реквизит 'Флаг':
    ДанныеТекущейСтроки.Флаг = Истина;
    // Сообщить("Значение флага для строки " + СчЦикла + ": " + ДанныеТекущейСтроки.Флаг);
КонецЦикла;

Однако этот метод имеет свои недостатки и считается менее предпочтительным по сравнению с прямым обходом коллекции Объект.ИмяТабличнойЧасти. Основная причина заключается в его ненадежности при интерактивном изменении табличной части. Если пользователь интерактивно удалит или переставит строки, индексы могут измениться, и ваш цикл, основанный на числовом индексе, может привести к ошибкам или некорректной обработке данных.

Метод ДанныеСтроки(Индекс) подходит для получения данных конкретной строки по известному индексу, но для полного циклического обхода коллекции Объект.ИмяТабличнойЧасти является более безопасным и надежным решением.

Особенности работы с ЭтотОбъект и ЭтаФорма в 1С 8.3

В контексте управляемых форм иногда возникает путаница с переменными ЭтотОбъект и ЭтаФорма. Давайте проясним их роль:

Понимание этой разницы критически важно для корректной работы с данными на управляемых формах.

Рекомендации по производительности: клиент или сервер?

Хотя обход табличной части на клиенте возможен и удобен для небольших объемов данных, всегда стоит учитывать производительность:

  1. Для малых объемов (до 20-30 строк): Обход на клиенте с использованием Объект.ИмяТабличнойЧасти вполне допустим и эффективен, особенно когда логика не требует обращения к базе данных или другим сложным серверным операциям.
  2. Для больших объемов данных: Если табличная часть содержит большое количество строк (сотни, тысячи), обход на клиенте может привести к снижению производительности. Платформа 1С передает данные ДанныеФормыКоллекция порциями. По мере обращения к новым порциям данных (например, при прокрутке или при полном обходе коллекции в цикле), могут происходить неявные серверные вызовы для подгрузки этих данных. Это может замедлить работу клиента.
  3. Сложная логика и запросы к базе данных: Если в цикле по табличной части нам необходимо выполнять сложные вычисления, обращаться к другим объектам базы данных, выполнять запросы или вызывать серверные процедуры, то всю эту логику однозначно следует переносить на сервер. Мы можем передать коллекцию данных с клиента на сервер, используя конструкции вида Док = ДанныеФормыВЗначение("Объект", Тип("ДокументОбъект.<ИмяДокумента>"));, а затем уже на сервере работать с ней как с обычным объектом базы данных.

Применяя эти подходы, мы сможем эффективно и надежно обходить табличные части на клиенте в управляемых формах 1С 8.3, избегая при этом распространенных ошибок и проблем с производительностью.

← На главную