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

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

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

Рассмотрим подробнее ситуацию, описанную в теме форума. У нас есть документ с реквизитом "Контактное лицо". При вводе нового, несуществующего контактного лица, система предлагает его создать. Автор хочет, чтобы при открытии формы создания нового контактного лица автоматически заполнялись два реквизита: "Наименование" (текст, введенный пользователем) и "Контрагент" (владелец, полученный из текущего документа).

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

Анализ исходной проблемы и попыток ее решения

В сообщении 0 автор описывает следующую ситуацию: при попытке создания нового контактного лица через событие Создание элемента формы:


&НаКлиенте
Процедура КонтактноеЛицоСоздание(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ПараметрыФормы = Новый Структура("Контрагент",Объект.Контрагент);
    ФормаВыбора = ПолучитьФорму("Справочник.КонтактныеЛицаКонтрагентов.ФормаОбъекта",ПараметрыФормы,ЭтаФорма);
    ФормаВыбора.ОткрытьМодально();
КонецПроцедуры

Здесь автор пытается передать параметр "Контрагент" через структуру ПараметрыФормы. В форме элемента контактного лица в обработчике ПриСозданииНаСервере он планирует проверять наличие параметра "Контрагент" и заполнять его. Однако, при таком подходе "Наименование" уже не заполняется автоматически платформой.

Почему наименование не заполняется?

Когда мы устанавливаем СтандартнаяОбработка = Ложь;, мы полностью отключаем стандартное поведение платформы. Стандартное поведение, помимо прочего, включает в себя передачу введенного текста в качестве значения для поля "Наименование" при создании нового элемента через поле ввода по строке. Поскольку мы отключаем стандартную обработку и открываем форму вручную, нам необходимо самостоятельно передавать все необходимые данные.

Решение 1: Передача всех параметров вручную через Структуру

Первое, что приходит на ум, и что предложено в сообщении 1, это передать "Наименование" также через структуру параметров:

Из сообщения 1:


(0) Передай его тоже параметром Новый Структура("Контрагент,Наименование",Объект.Контрагент,ТекНаименование);

Здесь ТекНаименование должно быть значением, введенным пользователем в поле ввода. Для получения этого значения мы можем использовать свойство Элемент.ТекстРедактирования, как это делает автор в сообщении 4.

Модифицированный код мог бы выглядеть так:


&НаКлиенте
Процедура КонтактноеЛицоСоздание(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ПараметрыФормы = Новый Структура();
    ПараметрыФормы.Вставить("Контрагент", Объект.Контрагент);
    ПараметрыФормы.Вставить("Наименование", Элемент.ТекстРедактирования); // Передаем введенный текст как наименование

    ФормаВыбора = ПолучитьФорму("Справочник.КонтактныеЛицаКонтрагентов.ФормаОбъекта", ПараметрыФормы, ЭтаФорма);
    ФормаВыбора.ОткрытьМодально();
КонецПроцедуры

Далее, в обработчике ПриСозданииНаСервере формы элемента справочника "КонтактныеЛицаКонтрагентов", нам необходимо было бы вручную обработать эти параметры:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("Контрагент") Тогда
        ЭтотОбъект.Владелец = Параметры.Контрагент; // Или другой реквизит, отвечающий за владельца
    КонецЕсли;
    Если Параметры.Свойство("Наименование") Тогда
        ЭтотОбъект.Наименование = Параметры.Наименование;
    КонецЕсли;
КонецПроцедуры

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

Решение 2: Использование параметра "ЗначенияЗаполнения" и свойства "Заполнять из данных заполнения"

Более элегантное и стандартное решение в управляемых формах 1С:Предприятия — это использование параметра ЗначенияЗаполнения при открытии формы и соответствующей настройки реквизитов объекта в конфигураторе. Об этом подходе упоминается в сообщении 3, ссылающемся на ИТС, и автор пытается его применить в сообщении 4.

Шаг 1: Передача параметров через ЗначенияЗаполнения

В форме документа, где мы инициируем создание нового контактного лица, изменяем код обработчика КонтактноеЛицоСоздание:


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

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

Как видно из сообщения 4, автор попытался использовать этот подход:


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

Это правильный код для передачи данных, но почему он "не срабатывает" (сообщение 4)? Причина кроется во втором важном шаге.

Шаг 2: Настройка свойства "Заполнять из данных заполнения" в конфигураторе

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

Из сообщения 6:


В общем у реквизитов объекта Контактные лица нужно поставить галочку "Заполнять из данных заполнения" и тогда работает

Давайте разберем этот шаг:

  1. Откройте конфигуратор.
  2. Перейдите к справочнику "КонтактныеЛицаКонтрагентов" (или другому справочнику, который вы создаете).
  3. Разверните ветку "Реквизиты".
  4. Для реквизита "Наименование":
    • Выделите реквизит "Наименование".
    • В окне "Свойства" найдите свойство "Заполнять из данных заполнения" и установите для него значение "Да" (галочка).
  5. Для реквизита "Контрагент" (который, вероятно, является владельцем):
    • Выделите реквизит "Контрагент" (или реквизит, связанный с владельцем, например, "Владелец").
    • В окне "Свойства" также установите для свойства "Заполнять из данных заполнения" значение "Да" (галочка).
  6. Сохраните конфигурацию базы данных.

После выполнения этих двух шагов (кодирование передачи ЗначенияЗаполнения и настройка реквизитов в конфигураторе), платформа 1С автоматически сопоставит ключи в структуре ЭлементыДляЗаполнения с именами реквизитов объекта и заполнит их соответствующими значениями. При этом вам не потребуется писать никакого кода в обработчике ПриСозданииНаСервере формы элемента для обработки этих параметров – платформа сделает это самостоятельно.

Преимущества этого подхода:

Решение 3: Использование обработчика "ОбработкаЗаполнения" в модуле объекта

Для более сложной логики заполнения, когда простого соответствия "имя параметра = имя реквизита" недостаточно, или когда требуется выполнить дополнительные проверки и вычисления, мы можем использовать обработчик события "ОбработкаЗаполнения" в модуле самого объекта (не формы).

Это событие вызывается при создании нового объекта интерактивно, при вводе на основании, а также при программном создании нового элемента, если ему передаются ДанныеЗаполнения. В этом обработчике мы получаем доступ к объекту, который создается, и к переданным данным.

Давайте посмотрим на пример, как это работает:

  1. Откройте конфигуратор.
  2. Перейдите к справочнику "КонтактныеЛицаКонтрагентов".
  3. Откройте "Модуль объекта".
  4. Вставьте следующий код:

// В модуле объекта Справочник.КонтактныеЛицаКонтрагентов
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    // Если мы передавали структуру через ЗначенияЗаполнения,
    // то ДанныеЗаполнения будут иметь тип Структура.
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
        // Проверим, есть ли в переданных данных Контрагент
        Если ДанныеЗаполнения.Свойство("Контрагент") Тогда
            ЭтотОбъект.Владелец = ДанныеЗаполнения.Контрагент;
        КонецЕсли;
        
        // Проверим, есть ли в переданных данных Наименование
        Если ДанныеЗаполнения.Свойство("Наименование") Тогда
            // Можно выполнить дополнительную логику, например, добавить префикс
            ЭтотОбъект.Наименование = "Новое: " + ДанныеЗаполнения.Наименование;
        КонецЕсли;
        
        // Дополнительный реквизит, например, Комментарий
        Если ДанныеЗаполнения.Свойство("Комментарий") Тогда
            ЭтотОбъект.Комментарий = ДанныеЗаполнения.Комментарий;
        КонецЕсли;

        // Если мы полностью обработали заполнение и не хотим, чтобы платформа
        // продолжала стандартное заполнение (например, через "Заполнять из данных заполнения"),
        // мы можем установить СтандартнаяОбработка = Ложь.
        // В данном случае, если нам нужны и эти механизмы, оставим СтандартнаяОбработка = Истина.
        // СтандартнаяОбработка = Ложь;
    Иначе
        // Если ДанныеЗаполнения - это ссылка на объект (например, при вводе на основании),
        // или Неопределено, можно обработать и эти случаи.
        // Например, ЭтотОбъект.Комментарий = "Создано без явных параметров";
    КонецЕсли;
    
    // СтандартнаяОбработка = Истина; // Позволит платформе продолжить заполнение,
                                     // например, использовать свойство "Заполнять из данных заполнения"
                                     // для тех реквизитов, которые не были заполнены здесь.
КонецПроцедуры

Как работает ОбработкаЗаполнения совместно с ЗначенияЗаполнения и "Заполнять из данных заполнения"?

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

  1. Первым делом вызывается обработчик события ОбработкаЗаполнения в модуле объекта. Здесь мы можем получить ДанныеЗаполнения (которые могут быть ссылкой, структурой или Неопределено) и выполнить нашу логику заполнения.
  2. Если в обработчике ОбработкаЗаполнения параметр СтандартнаяОбработка остался Истина, то платформа продолжает стандартное заполнение. В рамках этого стандартного заполнения она пытается использовать переданные через ПараметрыФормы.ЗначенияЗаполнения данные для реквизитов, у которых установлено свойство "Заполнять из данных заполнения".
  3. После этого, если какие-либо реквизиты все еще не заполнены (имеют значение типа по умолчанию), платформа использует "Значение заполнения", указанное непосредственно в конфигураторе для каждого реквизита.

Таким образом, ОбработкаЗаполнения дает нам наибольший контроль и позволяет реализовать самую сложную логику, в то время как ЗначенияЗаполнения в сочетании с "Заполнять из данных заполнения" обеспечивает удобный декларативный способ для типовых случаев.

Резюме и рекомендации

Для решения задачи, поставленной автором (заполнение "Наименования" и "Контрагента" при создании нового контактного лица из другой формы), наиболее эффективным и рекомендуемым является комбинированный подход:

  1. В коде обработчика события поля ввода в форме документа:

    Отключаем стандартную обработку и формируем структуру ЗначенияЗаполнения, передавая в нее все необходимые данные. Ключи структуры должны соответствовать именам реквизитов объекта, который мы создаем. Для поля, куда вводится текст, используем Элемент.ТекстРедактирования.

    
    &НаКлиенте
    Процедура КонтактноеЛицоСоздание(Элемент, СтандартнаяОбработка)
        СтандартнаяОбработка = Ложь;
        
        // Создаем структуру с данными для заполнения
        ДанныеДляЗаполнения = Новый Структура();
        ДанныеДляЗаполнения.Вставить("Контрагент", Объект.Контрагент);
        ДанныеДляЗаполнения.Вставить("Наименование", Элемент.ТекстРедактирования);
        
        // Передаем структуру в параметр ЗначенияЗаполнения формы
        ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ДанныеДляЗаполнения);
        
        // Открываем форму создания нового элемента
        ОткрытьФорму("Справочник.КонтактныеЛицаКонтрагентов.ФормаОбъекта", ПараметрыФормы, ЭтаФорма);
    КонецПроцедуры
    
  2. В конфигураторе для объекта "КонтактныеЛицаКонтрагентов":

    Для реквизитов "Наименование" и "Контрагент" (или "Владелец", если это реквизит владельца) устанавливаем свойство "Заполнять из данных заполнения" в значение "Да".

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

Такой подход обеспечивает чистоту кода, использует стандартные механизмы платформы 1С и является наиболее гибким для большинства сценариев автоматического заполнения новых объектов.

← На главную