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