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