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

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

При разработке на управляемых формах, особенно в веб-клиенте, мы часто сталкиваемся с необходимостью открыть пользователю список (например, справочник «Номенклатура» или «Контрагенты») для выбора одного или нескольких элементов, а затем обработать этот выбор в коде. Раньше для этого использовались модальные окна, блокирующие весь интерфейс программы. Однако современные стандарты разработки 1С и требования работы в веб-браузерах диктуют отказ от модальности.

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

Почему нельзя просто использовать модальные окна?

Многие из нас привыкли к методу ОткрытьФормуМодально(). Он кажется простым: код останавливается, ждет выбора пользователя и сразу возвращает результат. Однако у этого подхода есть критические недостатки:

  1. Блокировка интерфейса: Пользователь не может взаимодействовать ни с чем другим, пока не закроет окно.
  2. Несовместимость с Вебом: Большинство современных браузеров блокируют модальные окна, и платформа 1С в веб-клиенте просто не сможет выполнить такой код корректно или выдаст ошибку.
  3. Режим работы конфигурации: Во многих современных конфигурациях (ERP, КА, УТ) режим использования модальности отключен.

Поэтому мы разберем современные асинхронные методы работы.

Метод 1: Использование Описания Оповещения (Классический асинхронный подход)

Этот метод работает на всех версиях платформы 8.3 и является самым надежным для обеспечения совместимости. Суть метода заключается в том, что мы не «ждем» ответ в той же строке кода. Вместо этого мы говорим системе: «Открой форму, а когда пользователь что-то выберет, вызови вот эту процедуру». Если же стандартной формы выбора справочника недостаточно, в некоторых сценариях может пригодиться универсальная форма выбора типа.

Для этого нам понадобится объект ОписаниеОповещения. Давайте посмотрим, как это выглядит на практике. Предположим, у нас есть команда на форме, по которой нужно выбрать Контрагента.

Сначала напишем процедуру, которая инициирует открытие:


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

Обратите внимание: код в процедуре ПодобратьКонтрагента выполнится и завершится сразу. Система просто откроет окно и «забудет» о нем до момента закрытия. Теперь нам нужно описать саму процедуру обработки результата.


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

КонецПроцедуры

Передача контекста через ДополнительныеПараметры

Представим ситуацию сложнее: мы выбираем номенклатуру для конкретной строки табличной части. Нам нужно знать, в какую именно строку поместить результат.


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

КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораТовара(Результат, Параметры) Экспорт
    
    Если Результат = Неопределено Тогда 
        Возврат; 
    КонецЕсли;
    
    Идентификатор = Параметры.ИдентификаторСтроки;
    СтрокаТЧ = Объект.Товары.НайтиПоИдентификатору(Идентификатор);
    
    Если СтрокаТЧ <> Неопределено Тогда
        СтрокаТЧ.Номенклатура = Результат;
        ЗаполнитьЦенуНаСервере(СтрокаТЧ.ПолучитьИдентификатор());
    КонецЕсли;

КонецПроцедуры

Метод 2: Современный синтаксис Async / Await (Платформа 8.3.18+)

Начиная с версии платформы 8.3.18, 1С ввела синтаксис, который делает асинхронный код похожим на синхронный. Чтобы освоить `Async/Await` на практике, мы используем ключевые слова Ждать (Await) и Асинх (Async).


&НаКлиенте
Асинх Процедура ПодобратьКонтрагента(Команда)
    
    ПараметрыОткрытия = Новый Структура("РежимВыбора", Истина);
    
    Попытка
        Результат = Ждать ОткрытьФормуАсинх("Справочник.Контрагенты.ФормаВыбора", ПараметрыОткрытия, ЭтотОбъект);
        
        Если Результат <> Неопределено Тогда
            Объект.Контрагент = Результат;
            Сообщить("Выбран: " + Строка(Результат));
        Иначе
            Сообщить("Пользователь отказался от выбора");
        КонецЕсли;
        
    Исключение
        Сообщить("Произошла ошибка при открытии: " + ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Сложные сценарии: Множественный выбор

Часто возникает задача дать пользователю возможность выбрать сразу несколько позиций.

Правильный способ активировать множественный выбор при программном открытии:


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

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

КонецПроцедуры

Тонкости и типичные ошибки

  1. Владелец формы (третий параметр ОткрытьФорму).

    Всегда передавайте ЭтотОбъект в качестве владельца. Если вам нужно изучить или изменить свойства элементов формы «на лету», используйте редактор форм в режиме предприятия.

  2. Обработка "Неопределено".

    Никогда не забывайте проверять Если Результат <> Неопределено, чтобы избежать ошибок при закрытии формы нажатием Esc.

  3. Передача управления на сервер.

    Обработчик оповещения выполняется &НаКлиенте. Для сложных серверных операций вызывайте соответствующие функции модуля.

  4. Экспортность процедур.

    Процедура-обработчик должна быть доступна платформе.

Резюме

Для решения задачи выбора значений программно мы выяснили следующее:

← На главную