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