При разработке управляемых форм в платформе 1С:Предприятие 8 разработчики нередко сталкиваются с ситуацией, когда безобидный вызов серверной процедуры или функции приводит к аварийному завершению работы формы со служебной ошибкой: «Отсутствует отображение для типа 'ЭлементСпискаЗначений'». При этом ошибка может появляться даже в том случае, если разработчик явно не передает списки в параметры вызываемого метода. Проанализируем механику клиент-серверного взаимодействия, выясним первопричину этой ошибки и разберем практические способы её устранения.
Разберем, что происходит при выполнении кода в управляемой форме. Когда мы вызываем процедуру или функцию с директивой &НаСервере, платформа автоматически выполняет полную сериализацию текущего контекста формы. Это означает, что все реквизиты формы, включая основной реквизит Объект (со всеми его реквизитами, табличными частями и коллекциями), упаковываются во внутренний формат обмена (XDTO) и отправляются на сервер. Даже если внутри серверной функции мы обращаемся только к одному простому реквизиту вроде Объект.Пользователь, сериализуется абсолютно вся форма целиком.
Сам по себе тип СписокЗначений является сериализуемым и успешно передается между клиентом и сервером. Однако отдельный объект ЭлементСпискаЗначений (служебный элемент коллекции) не входит в перечень типов, поддерживающих сериализацию XDTO. Ошибка «Отсутствует отображение для типа 'ЭлементСпискаЗначений'» возникает ровно в тот момент, когда платформа пытается сериализовать данные формы, в которых внутри свойства Значение одного из элементов списка оказался помещен сам объект ЭлементСпискаЗначений.
Посмотрим на типичный ошибочный код, приводящий к этой коллизии на клиенте:
// Ошибочный вариант: в новый список кладется сам объект элемента
Для Каждого Элемент Из ИсходныйСписок Цикл
НовыйСписок.Добавить(Элемент); // Ошибка! Свойство Значение получит тип ЭлементСпискаЗначений
КонецЦикла;
Пока такой список находится исключительно на стороне клиента, программа работает без видимых сбоев. Но как только форма инициирует контекстный вызов &НаСервере, платформа пытается преобразовать все реквизиты в XML-поток и падает, не найдя правила сериализации для вложенного служебного типа.
Если для работы серверного алгоритма не требуется изменять весь объект или обращаться ко всем элементам формы, самым правильным архитектурным решением является отказ от передачи контекста формы. Рассмотрим подробнее, как переписать вызов.
Вместо передачи контекста формы мы используем директиву &НаСервереБезКонтекста, а необходимые для расчета или запроса данные передаем явно через параметры метода. Это не только решает проблему с передачей некорректных реквизитов, но и существенно ускоряет работу программы за счет снижения сетевого трафика между клиентом и сервером.
Разберем по шагам правильную реализацию на примере:
&НаСервереБезКонтекста
Функция ПолучитьДанныеПоПользователю(ПользовательСсылка)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Пользователи.Наименование КАК Имя,
| Пользователи.Недействителен КАК Недействителен
|ИЗ
| Справочник.Пользователи КАК Пользователи
|ГДЕ
| Пользователи.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ПользовательСсылка);
РезультатЗапроса = Запрос.Выполнить();
// Обработка результата и формирование возвращаемой структуры
Структура = Новый Структура;
// ... заполнение структуры
Возврат Структура;
КонецФункции
&НаКлиенте
Процедура ПользовательПриИзменении(Элемент)
// Передаем только конкретную ссылку, минуя контекст формы
СтруктураДанных = ПолучитьДанныеПоПользователю(Объект.Пользователь);
// Обрабатываем результат на клиенте
РеквизитСписок = ПреобразованиеСтруктуры(СтруктураДанных);
КонецПроцедуры
Обратим внимание на частую ошибку: директива &НаКлиентеНаСервереБезКонтекста предназначена для универсальных вспомогательных функций (например, математических расчетов или работы со строками). В ней нельзя выполнять объектные операции с базой данных, такие как Запрос, так как при исполнении на клиенте они не поддерживаются. Если вам требуется выполнить запрос к базе данных, используйте строго &НаСервереБезКонтекста.
Если серверный контекст формы все-таки необходим для работы (например, для модификации самого документа или его табличных частей), необходимо устранить корень проблемы — исключить появление несериализуемых объектов внутри коллекций формы.
Проанализируем процедуру преобразования и наполнения списка значений. При копировании элементов или обработке выбора из списков всегда нужно явно извлекать прикладное значение и строковое представление:
// Корректное заполнение одного списка из другого
Для Каждого ЭлементИсточника Из ИсходныйСписок Цикл
// Явно передаем значение и представление, а не объект целиком
ПриемникСписок.Добавить(ЭлементИсточника.Значение, ЭлементИсточника.Представление);
КонецЦикла;
Аналогичная ошибка часто возникает в обработчиках событий полей ввода (например, ОбработкаВыбора). Если в реквизит формы ошибочно присваивается сам объект выбора, а не его свойство:
// Ошибочно:
РеквизитФормы = ВыбранноеЗначение; // Если ВыбранноеЗначение имеет тип ЭлементСпискаЗначений
// Корректно:
Если ТипЗнч(ВыбранноеЗначение) = Тип("ЭлементСпискаЗначений") Тогда
РеквизитФормы = ВыбранноеЗначение.Значение;
Иначе
РеквизитФормы = ВыбранноеЗначение;
КонецЕсли;
Если форма содержит множество реквизитов и определить источник ошибки сходу не удается, разберем по шагам диагностику перед проблемным серверным вызовом:
Для Каждого Элемент Из Список1 Цикл
ТипВнутри = ТипЗнч(Элемент.Значение);
Если ТипВнутри = Тип("ЭлементСпискаЗначений") Тогда
Сообщить("Найден несериализуемый элемент в Список1!");
КонецЕсли;
КонецЦикла;
Соблюдение правил типизации данных и осознанный выбор между контекстными и внеконтекстными серверными вызовами позволяет избежать непредвиденных ошибок сериализации и обеспечивает стабильную работу управляемого интерфейса.