Как реализовать динамическое добавление и удаление реквизитов на форме с сохранением данных

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

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

Проблема «исчезающих» данных

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

Чтобы данные сохранялись, их нужно «приземлять» в базу данных. Разберем основные стратегии решения этой задачи, от простых к более сложным и гибким.

Решение 1: Использование табличной части (Рекомендуемый подход)

Прежде чем приступать к сложному программному коду, проанализируем ситуацию: не изобретаем ли мы велосипед? В 90% случаев для ввода списка однотипных данных (как номера телефонов) идеально подходит Табличная часть объекта. Она уже обладает встроенными механизмами хранения, добавления и удаления строк.

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

  1. Данные автоматически записываются при сохранении документа или справочника.
  2. Не нужно использовать ресурсоемкий метод ИзменитьРеквизиты.
  3. Легко реализовать проверку уникальности или формата данных.

Решение 2: Управление видимостью заранее созданных реквизитов

Если вы точно знаете, что пользователю вряд ли понадобится более, например, 10 полей, мы можем применить метод «запаса». Создадим в конфигураторе 10 реквизитов (Телефон1, Телефон2... Телефон10) и соответствующие им элементы формы. По умолчанию установим свойство Видмость в значение Ложь.

Проанализируем пример кода для управления видимостью:


&НаКлиенте
Процедура УстановитьКоличествоПолей(Количество)
    Для Сч = 1 По 10 Цикл
        ИмяЭлемента = "Телефон" + Сч;
        Элементы[ИмяЭлемента].Видимость = (Сч <= Количество);
    КонецЦикла;
КонецПроцедуры

Этот подход считается наиболее производительным, так как не требует перестроения структуры формы на сервере. Форма просто скрывает или показывает уже готовые элементы. Однако он ограничен жестким лимитом полей.

Решение 3: Программное создание через ИзменитьРеквизиты

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

Важное правило: Метод ИзменитьРеквизиты вызывает полную инициализацию формы, что крайне нагружает сервер. Поэтому никогда не вызывайте его внутри цикла. Сначала сформируем массивы добавляемых и удаляемых реквизитов.

Разберем пример создания полей для ввода телефонов:


&НаСервере
Процедура ДобавитьРеквизитыНаФорму(Количество)
    
    МассивДобавляемых = Новый Массив;
    МассивУдаляемых = Новый Массив;
    
    // Сначала определим, какие старые реквизиты нужно удалить
    // (например, если мы уменьшаем количество с 7 до 5)
    Для Каждого Реквизит Из ЭтаФорма.ПолучитьРеквизиты() Цикл
        Если СтрНайти(Реквизит.Имя, "ДинамическийТелефон_") > 0 Тогда
            МассивУдаляемых.Добавить(Реквизит.Имя);
        КонецЕсли;
    КонецЦикла;
    
    // Подготовим новые реквизиты
    Для Сч = 1 По Количество Цикл
        ТипРеквизита = Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(20));
        НовыйРеквизит = Новый РеквизитФормы("ДинамическийТелефон_" + Сч, ТипРеквизита, , "Телефон №" + Сч);
        МассивДобавляемых.Добавить(НовыйРеквизит);
    КонецЦикла;
    
    // Выполняем изменение ОДИН раз
    ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемых, МассивУдаляемых);
    
    // Теперь создаем визуальные элементы
    Для Сч = 1 По Количество Цикл
        ИмяРеквизита = "ДинамическийТелефон_" + Сч;
        НовыйЭлемент = Элементы.Добавить(ИмяРеквизита, Тип("ПолеФормы"), ЭтаФорма);
        НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
        НовыйЭлемент.ПутьКДанным = ИмяРеквизита;
    КонецЦикла;
    
КонецПроцедуры

Как сохранить динамические данные?

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

Предположим, у нашего справочника есть реквизит ДополнительныеДанныеТелефонов с типом ХранилищеЗначений или Строка (неограниченная). Посмотрим на алгоритм сохранения:

  1. В событии ПередЗаписьюНаСервере мы обходим все наши динамические реквизиты.
  2. Собираем их значения в структуру или соответствие.
  3. Преобразуем структуру в строку JSON или XML.
  4. Записываем эту строку в реквизит объекта.

Пример восстановления данных в событии ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // 1. Читаем строку из объекта
    ДанныеСтрокой = Объект.ДополнительныеДанныеТелефонов;
    // 2. Десериализуем (например, из JSON)
    СтруктураДанных = ПрочитатьJSON(ДанныеСтрокой); 
    // 3. Создаем реквизиты на форме (как в Решении 3)
    ДобавитьРеквизитыНаФорму(СтруктураДанных.Количество());
    // 4. Заполняем созданные реквизиты данными
    Для Каждого ЭлементДанных Из СтруктураДанных Цикл
        ЭтаФорма[ЭлементДанных.Ключ] = ЭлементДанных.Значение;
    КонецЦикла;
КонецПроцедуры

Альтернатива: Использование БСП

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), проанализируем возможность использования механизма «Дополнительные реквизиты и сведения». Это штатный, мощный и уже отлаженный инструмент, который позволяет пользователям в режиме «1С:Предприятие» добавлять новые поля к объектам без привлечения программиста. Данные в этом случае хранятся в специальном регистре сведений, а их вывод на форму берет на себя подсистема БСП.

Для задачи с телефонами также идеально подходит подсистема «Контактная информация». Она поддерживает хранение нескольких телефонов одного вида, проверку масок ввода и хранение истории изменений. Вместо написания кода с нуля, мы рекомендуем настроить виды контактной информации в соответствующем справочнике.

Порядок удаления элементов

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

Правильный алгоритм удаления:

  1. Сначала находим и удаляем визуальные элементы через Элементы.Удалить(ИмяЭлемента).
  2. Только после этого вызываем ИзменитьРеквизиты, передавая имена реквизитов в массиве удаляемых.

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

← На главную