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