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