Как программно добавить дополнительные реквизиты и поля ввода на форму в 1С:Предприятие 8.3?

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

При разработке конфигураций часто возникает задача предоставить пользователю возможность самостоятельно расширять состав реквизитов объектов. Например, добавлять произвольные свойства («Цвет», «Размер», «Тип карты») к элементам справочника с возможностью выбора предопределенных значений. Разберем, как спроектировать структуру метаданных, программно сгенерировать реквизиты и элементы управления на управляемой форме, а также сохранить введенные данные.

Архитектура хранения дополнительных свойств

Для реализации гибкого механизма дополнительных реквизитов обычно используется классическая связка объектов метаданных:

  1. План видов характеристик (ПВХ) СвойстваКошельков: определяет перечень доступных свойств и допустимые типы их значений. В качестве типа значения указывается составной тип или ссылка на справочник значений.
  2. Справочник ДополнительныеСвойстваКошельков: подчинен ПВХ (владелец — ПланВидовХарактеристикСсылка.СвойстваКошельков) и хранит список конкретных вариантов значений для каждого свойства (например, для свойства «Цвет» — «Черный», «Белый»).
  3. Регистр сведений ЗначенияСвойствКошельков: независимый регистр сведений для хранения установленных значений. Измерения: Объект (ссылка на элемент справочника) и ВидСвойства (ссылка на ПВХ). Ресурс: Значение (тип Характеристика.СвойстваКошельков).

Также альтернативным вариантом является использование табличной части у самого объекта (с колонками Свойство и Значение), что исключает необходимость отдельного регистра сведений и гарантирует целостность записи в одной транзакции.

Динамическое создание реквизитов и элементов на управляемой форме

Выясним, как отобразить созданные свойства на форме объекта. На управляемой форме нельзя напрямую привязать поле к записи регистра сведений, поэтому при открытии формы необходимо программно создать реквизиты формы, связать их с новыми полями ввода и заполнить сохраненными значениями.

Проанализируем серверную процедуру инициализации и отрисовки динамических полей:


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

Важные правила работы с методом ИзменитьРеквизиты

При программной модификации реквизитов формы следует соблюдать ключевые ограничения платформы:

  1. Пакетное добавление: Метод ИзменитьРеквизиты выполняет тяжелую операцию переинициализации контекста формы. Категорически не рекомендуется вызывать его внутри цикла. Все добавляемые реквизиты необходимо поместить в один массив и передать методу единожды.
  2. Правила именования: Имя реквизита формы подчиняется общим правилам идентификаторов 1С. Оно не может начинаться с цифры, содержать спецсимволы и пробелы. Рекомендуется использовать фиксированный префикс (например, ДопСвойство_).
  3. Доступ к значениям: Обращение к созданному реквизиту по строковому имени выполняется через синтаксис квадратных скобок: ЭтаФорма[ИмяРеквизита].

Организация диалога добавления свойства и сохранение данных

Рассмотрим, как организовать интерактивное добавление нового реквизита по кнопке на форме объекта с последующим обновлением интерфейса.

На клиенте вызываем открытие формы создания записи регистра сведений:


&НаКлиенте
Процедура ДобавитьХарактеристику(Команда)
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Кошелек", Объект.Ссылка);
    
    Оповещение = Новый ОписаниеОповещения("ПослеДобавленияСвойства", ЭтаФорма);
    ОткрытьФорму("РегистрСведений.ЗначенияСвойствКошельков.ФормаЗаписи", ПараметрыОткрытия, ЭтаФорма, , , , Оповещение);
КонецПроцедуры

&НаКлиенте
Процедура ПослеДобавленияСвойства(Результат, ДополнительныеПараметры) Экспорт
    // Перечитываем состав динамических свойств после добавления
    ЗагрузкаСпискаХарактеристик();
КонецПроцедуры

В форме записи регистра сведений принимаем переданный объект и возвращаем управление:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("Кошелек") Тогда
        Запись.Объект = Параметры.Кошелек;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Закрыть(Истина);
КонецПроцедуры

Настройка фильтрации значений по свойству-владельцу

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

Для корректного отбора подчиненного справочника по владельцу используется свойство поля ПараметрыВыбора. Поскольку ссылка на элемент ПВХ (владелец) известна на этапе генерации поля, мы передаем фиксированный массив с отбором Отбор.Владелец. Это гарантирует, что в списке выбора пользователь увидит только допустимые значения конкретного свойства.

← На главную