Почему не возвращается значение из формы выбора в 1С и как это исправить?

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

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

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

Анализ проблемы: почему не отрабатывает возврат значения?

Рассмотрим код, который часто пишут начинающие разработчики в обработчике события начала выбора (например, для поля Топливо):


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

В данном примере разработчик пытается передать в качестве третьего параметра функции ОткрытьФорму значение реквизита Запись.Топливо. В этом и кроется ключевая ошибка.

Третьим параметром функции ОткрытьФорму передается Владелец формы. Платформа «1С:Предприятие» использует владельца для того, чтобы знать, куда именно отправить оповещение о сделанном выборе. Владельцем может выступать либо другая форма (ЭтаФорма), либо конкретный элемент управления на форме (например, Элемент типа ПолеФормы).

Когда мы передаем Запись.Топливо, мы передаем обычную ссылку на элемент справочника (тип СправочникСсылка.Номенклатура). Ссылка в базе данных не является интерактивным объектом интерфейса. Она не умеет принимать оповещения от платформы и не содержит обработчиков событий. В результате форма выбора открывается «в пустоту» — система не знает, кто инициировал выбор, и выбранное значение бесследно теряется при закрытии окна.

Решение №1: Передача элемента формы в качестве владельца

Самый простой и правильный способ решить проблему в рамках стандартного синхронного вызова — передать в качестве владельца сам элемент управления, который инициировал выбор. Этот элемент автоматически передается в первый параметр предопределенной процедуры НачалоВыбора под именем Элемент.

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


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

Как это работает под капотом:

  1. Установка свойства СтандартнаяОбработка = Ложь отменяет открытие формы выбора по умолчанию.
  2. Метод ОткрытьФорму открывает указанную форму выбора и связывает её с элементом формы Элемент (нашим полем ввода).
  3. Когда пользователь выбирает номенклатуру в списке, платформа видит, что владельцем формы выбора является конкретное поле ввода.
  4. Платформа автоматически помещает выбранную ссылку в связанный с полем реквизит (в нашем случае Запись.Топливо) и обновляет отображение на экране.
  5. Автоматически вызываются события ПриИзменении для этого элемента формы. Нам даже не требуется писать код для ручной обработки выбора.

Решение №2: Использование асинхронного вызова через ОписаниеОповещения

В современных конфигурациях 1С, особенно работающих в Web-клиенте или на мобильных платформах, хорошим тоном является использование асинхронных вызовов. Это предотвращает блокировку интерфейса и обеспечивает стабильную работу в любых браузерах.

Для асинхронного возврата значения используется объект ОписаниеОповещения. Посмотрим на практический пример реализации:


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

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

Обратите внимание, что процедура-получатель (в нашем примере ТопливоОбработкаВыбора) обязательно должна быть объявлена с директивой экспорта (Экспорт), иначе платформа не сможет вызвать её из внешней формы.

Решение исходной задачи: программная установка отбора

Вернемся к исходной задаче автора темы: необходимо не просто открыть форму выбора номенклатуры, но и отфильтровать список так, чтобы пользователь видел только позиции с типом «Топливо».

Для этого нам нужно передать параметры отбора в открываемую форму. У всех стандартных форм выбора динамических списков есть встроенный параметр Отбор, принимающий структуру. Имена ключей в этой структуре должны строго соответствовать именам реквизитов справочника.

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


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

Альтернатива: Декларативная настройка в Конфигураторе (Best Practice)

Написание программного кода в событии НачалоВыбора для простых отборов в современной разработке считается избыточным. Платформа «1С:Предприятие» предоставляет мощный инструмент декларативной настройки свойств, который работает быстрее и не требует поддержки кода.

Если вам нужно жестко ограничить выбор реквизита на форме, выполните следующие шаги в конфигураторе:

  1. Откройте форму, на которой расположено поле ввода (в случае автора — форму регистра сведений).
  2. Найдите нужный элемент формы (поле ввода Топливо) и откройте его палитру свойств.
  3. Найдите свойство Параметры выбора (Choice parameters).
  4. Нажмите на кнопку открытия параметров и добавьте новую строку:
    • Имя параметра: Отбор.ТипНоменклатуры
    • Значение: укажите необходимое значение (например, предопределенное значение перечисления или конкретный элемент).
  5. Если отбор должен применяться глобально для этого реквизита во всех формах системы, настройте свойство Параметры выбора непосредственно у реквизита в дереве метаданных объекта (в самом регистре сведений), а не на конкретной форме.

После такой настройки платформа автоматически, без единой строчки кода, будет накладывать необходимый фильтр при открытии формы выбора и корректно возвращать результат в поле ввода.

← На главную