Как исправить ошибку «Отсутствует отображение для типа ЭлементСпискаЗначений» при выборе из списка в управляемой форме?

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

При разработке интерфейсов на управляемых формах платформы 1С:Предприятие 8.3 разработчики часто реализуют кастомный выбор из выпадающего списка с помощью асинхронного метода ПоказатьВыборИзСписка. Однако в процессе выполнения кода может возникнуть критическая ошибка сериализации XDTO:

«Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа... Ошибка отображения типов: Отсутствует отображение для типа 'ЭлементСпискаЗначений'».

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

Причины возникновения ошибки XDTO

Выясним причину падения платформы. Ошибка возникает на стыке двух особенностей клиент-серверного взаимодействия управляемого приложения:

  1. Директива компиляции по умолчанию. Если в модуле управляемой формы объявить процедуру или функцию без явного указания директивы (например, без &НаКлиенте или &НаСервере), платформа 1С по умолчанию считает её процедурой с контекстом сервера — &НаСервере.
  2. Невозможность передачи типа ЭлементСпискаЗначений через границу контекстов. Коллекция СписокЗначений поддерживает сериализацию XDTO и может передаваться между клиентом и сервером. Однако отдельный объект ЭлементСпискаЗначений отображения в XDTO не имеет. Платформа не умеет передавать его с клиента на сервер в качестве параметра вызова.
  3. Поведение метода ПоказатьВыборИзСписка. После интерактивного выбора элемента в окне платформа вызывает указанную процедуру оповещения и передает в её первый параметр именно объект типа ЭлементСпискаЗначений (или Неопределено, если пользователь прервал выбор). Так как процедура оповещения не имела директивы &НаКлиенте, клиентский сеанс попытался выполнить серверный вызов, передав туда несериализуемый объект ЭлементСпискаЗначений, что вызвало исключение.

Решение 1. Явное указание директивы &НаКлиенте для обработчика оповещения

Разберем по шагам, как исправить исходный код. Процедуры обратного вызова (оповещения) для модальных и асинхронных интерфейсных методов платформы всегда должны выполняться в контексте клиента. Добавим директиву &НаКлиенте и обратимся к свойству Значение выбранного элемента.

Посмотрим на исправленный фрагмент модуля формы:


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

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

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

Обратим внимание на следующие оптимизации в коде:

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

Решение 2. Использование стандартного параметра «ДанныеВыбора»

Рассмотрим альтернативный способ, который в большинстве случаев оказывается проще и лаконичнее. В обработчике события поля ввода НачалоВыбора платформа предоставляет параметр ДанныеВыбора.

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

Посмотрим на пример кода:


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

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

← На главную