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

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

При разработке на управляемых формах 1С:Предприятия 8.3 разработчики часто сталкиваются с ошибкой «Использование модальных окон в данном режиме запрещено!». Эта ситуация возникает при попытке вызвать синхронные методы, такие как ВыбратьЭлемент у списка значений, ОткрытьФормуМодально, ВвестиЗначение или Вопрос, когда в свойствах конфигурации режим использования модальности установлен в значение «Не использовать».

Разберем типичную практическую задачу: в динамическом списке пользователь нажимает на ячейку строки, после чего программа должна запросить у него выбор нужного значения из базы (или ручной ввод) и записать результат в соответствующий объект. Разберем по шагам, как правильно реализовать этот сценарий с использованием асинхронных вызовов.

Выясним причину ошибки и архитектурный подход

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

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

  1. Быстрый немодальный выбор без создания отдельной формы — с помощью встроенных методов ПоказатьВыборИзСписка, ПоказатьВыборЭлемента или ПоказатьВводЗначения.
  2. Открытие отдельной формы выбора — когда требуется сложный интерфейс с поиском, таблицами и дополнительными полями ввода.

Вариант 1. Использование встроенных асинхронных методов выбора

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

Проанализируем пример оптимизированного кода в модуле формы:


&НаСервереБезКонтекста
Функция ПолучитьМассивИдентификаторовНаСервере(Владелец)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    ЗначенияСвойствОбъектов.Б_Идентификатор КАК Б_Идентификатор
        |ИЗ
        |    Справочник.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
        |ГДЕ
        |    ЗначенияСвойствОбъектов.Владелец = &Владелец";
    Запрос.УстановитьПараметр("Владелец", Владелец);
    
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Б_Идентификатор");
КонецФункции

&НаСервереБезКонтекста
Процедура ЗаписатьИдентификаторВОбъект(КодБитрикса, Владелец)
    ВладелецОбъект = Владелец.ПолучитьОбъект();
    ВладелецОбъект.Б_Идентификатор = КодБитрикса;
    ВладелецОбъект.Записать();
КонецПроцедуры

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

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

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

Вариант 2. Открытие собственной формы выбора во внешней обработке

Если для выбора требуется отдельная форма (например, форма с таблицей, поиском и специализированными элементами управления), ее необходимо открывать немодально через функцию ОткрытьФорму с передачей обработчика закрытия.

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

  1. В модуле основной формы формируем параметры, создаем ОписаниеОповещения и открываем подчиненную форму:

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

&НаКлиенте 
Функция ПолучитьПолноеИмяФормы(ИмяФормы)
    СимволТочка = ".";
    ПозицияТочки = СтрДлина(ЭтаФорма.ИмяФормы);
    Пока Сред(ЭтаФорма.ИмяФормы, ПозицияТочки, 1) <> СимволТочка Цикл 
        ПозицияТочки = ПозицияТочки - 1; 
    КонецЦикла;
    Возврат Лев(ЭтаФорма.ИмяФормы, ПозицияТочки) + ИмяФормы;
КонецФункции

&НаКлиенте
Процедура ПослеЗакрытияФормыВыбора(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
    Если РезультатЗакрытия <> Неопределено Тогда
        ЗаписатьИдентификаторВОбъект(РезультатЗакрытия, ДополнительныеПараметры.Владелец);
        ОповеститьОбИзменении(ДополнительныеПараметры.Владелец);
    КонецЕсли;
КонецПроцедуры
  1. В модуле формы выбора принимаем параметры при создании и возвращаем результат при выборе:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("МассивКодовБитрикса") Тогда
        // Заполняем реквизит формы типа СписокЗначений
        СписокКодов.ЗагрузитьЗначения(Параметры.МассивКодовБитрикса);
    КонецЕсли;
КонецПроцедуры

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

&НаКлиенте
Процедура КнопкаПрименитьВручную(Команда)
    Если Не ПустаяСтрока(РеквизитРучногоВвода) Тогда
        Закрыть(РеквизитРучногоВвода);
    КонецЕсли;
КонецПроцедуры

Критические правила работы с асинхронными вызовами

Обратим внимание на обязательные требования платформы 1С при работе с обработчиками оповещений:

  1. Директивы и видимость процедур: Процедура, указанная в ОписаниеОповещения, обязана быть объявлена с директивой &НаКлиенте и ключевым словом Экспорт. Попытка объявить процедуру-обработчик на сервере приведет к исключению во время закрытия диалога.
  2. Сигнатура параметров: Процедура закрытия формы должна принимать ровно два параметра: (РезультатЗакрытия, ДополнительныеПараметры). Для методов выбора из списка сигнатура имеет вид: (ВыбранныйЭлемент, ДополнительныеПараметры).
  3. Обновление интерфейса: Запись объекта на сервере через метод Записать() не обновляет автоматически данные в открытом динамическом списке на клиенте. Чтобы строка отобразила новые данные без полного перезапуска формы, необходимо вызвать метод ОповеститьОбИзменении(СсылкаНаОбъект) или Элементы.ИмяСписка.Обновить().
← На главную