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