Как передать данные из строки дерева или таблицы значений с клиента на сервер в 1С?

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

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

Почему возникает ошибка передачи данных?

Проанализируем ситуацию: когда вы обращаетесь к свойству Элементы.ИмяСписка.ТекущиеДанные, платформа возвращает объект типа ДанныеФормыЭлементДерева или ДанныеФормыЭлементКоллекции. Эти объекты являются так называемыми «прокси-объектами» или проекциями данных, которые живут только в контексте формы на стороне клиента. Они не являются сериализуемыми — это значит, что платформа не может превратить их в поток байтов (XML или JSON) для отправки по сети на сервер.

Многие начинающие разработчики пытаются «обхитрить» систему, помещая такую строку в структуру или массив: Структура.Вставить("Данные", Элемент.ТекущиеДанные). Однако, как верно подмечено в обсуждении, «спрятать значение в яйцо, а яйцо в утку» не получится. При вызове сервера платформа выполняет глубокую проверку всех вложенных элементов. Как только она натыкается на недопустимый тип данных внутри вашего массива, происходит критическая ошибка XDTO.

Способ 1: Передача конкретных значений через структуру

Самый простой и правильный путь — извлечь из строки нужные вам данные (числа, строки, даты, ссылки) и поместить их в структуру. Эти типы данных являются примитивными или ссылочными, и 1С умеет их сериализовать без проблем.

Рассмотрим пример, когда нам нужно передать данные о выбранной номенклатуре:


// Код на клиенте
&НаКлиенте
Процедура ОбработатьВыбор(Элемент)
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Формируем структуру с простыми данными
    ДанныеДляСервера = Новый Структура;
    ДанныеДляСервера.Вставить("Номенклатура", ТекущаяСтрока.Номенклатура);
    ДанныеДляСервера.Вставить("Количество",   ТекущаяСтрока.Количество);
    ДанныеДляСервера.Вставить("Цена",         ТекущаяСтрока.Цена);
    
    // Теперь эту структуру можно смело передавать на сервер
    ВыполнитьОбработкуНаСервере(ДанныеДляСервера);
КонецПроцедуры

Способ 2: Использование идентификатора строки

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

Разберем этот алгоритм по шагам:

  1. На клиенте получаем идентификатор текущей строки через метод ПолучитьИдентификатор().
  2. Передаем это число на сервер.
  3. На сервере используем метод НайтиПоИдентификатору() для получения доступа к данным.

Пример реализации:


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

&НаСервере
Процедура ОбработатьСтрокуНаСервере(Идентификатор)
    // Ищем строку в реквизите формы "ДеревоНоменклатуры"
    СтрокаДерева = ДеревоНоменклатуры.НайтиПоИдентификатору(Идентификатор);
    
    Если СтрокаДерева <> Неопределено Тогда
        // Здесь нам доступны все данные строки и её подчиненные элементы
        Сообщить("Выбрано: " + СтрокаДерева.Наименование);
        
        Для Каждого ПодчиненнаяСтрока Из СтрокаДерева.ПолучитьЭлементы() Цикл
            // Обработка вложенных строк
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Способ 3: Обход иерархии (для деревьев значений)

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

Выясним, как это сделать эффективно:


&НаКлиенте
Функция СформироватьМассивДанных(СтрокаДерева)
    Результат = Новый Массив;
    
    Для Каждого ДочернийЭлемент Из СтрокаДерева.ПолучитьЭлементы() Цикл
        СтруктураСтроки = Новый Структура;
        СтруктураСтроки.Вставить("Наименование", ДочернийЭлемент.Наименование);
        СтруктураСтроки.Вставить("Код",          ДочернийЭлемент.Код);
        
        // Рекурсивно собираем подчиненные строки
        СтруктураСтроки.Вставить("ВложенныеСтроки", СформироватьМассивДанных(ДочернийЭлемент));
        
        Результат.Добавить(СтруктураСтроки);
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

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

Важные рекомендации

Проанализировав проблему, можно выделить несколько «золотых правил» работы с данными в управляемом интерфейсе:

Таким образом, решение проблемы кроется в понимании архитектуры 1С:Предприятие 8. Разделение данных на «интерфейсные объекты» и «чистые данные» позволяет платформе работать быстро и стабильно в веб-клиенте и тонком клиенте. Используя вышеописанные методы (структуры или идентификаторы), вы навсегда избавитесь от ошибок XDTO при передаче параметров.

← На главную