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