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