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