Почему возникает ошибка «Процедура или функция с указанным именем не определена» при вызове клиентского метода из серверного в 1С?

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

При разработке управляемых форм в платформе 1С:Предприятие 8.3 разработчики нередко сталкиваются с ситуацией, когда процедура визуально присутствует в модуле формы, но при синтаксической проверке или выполнении кода возникает ошибка компиляции вида:

{Отчет.Статистика.Форма.ФормаОтчета.Форма(12,3)}: Процедура или функция с указанным именем не определена (ВывестиТзВМакет) <<?>>ВывестиТзВМакет(Тз); (Проверка: Сервер)

Разберем детально, почему платформа не видит объявленную процедуру, как устроена модель взаимодействия тонкого клиента и сервера, а также как правильно переписать алгоритм формирования отчета.

Причина ошибки: директивы компиляции и контекст выполнения

Проанализируем исходный фрагмент кода, вызвавший ошибку:


&НаСервере
Процедура СформироватьНаСервере()
    Тз = СоздатьТЗ();
    Если Тз <> 0 Тогда
        ВывестиТзВМакет(Тз);
    Иначе
        Сообщить("Нет данных для выборки!");
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ВывестиТзВМакет(Тз)
    МакетОтчета = ПолучитьМакетНаСервере();
    // ...
КонецПроцедуры

Причина ошибки заключается в несовместимости контекстов выполнения и правил использования директив компиляции:

  1. Однонаправленность клиент-серверных вызовов. В архитектуре управляемого приложения клиентская часть знает о сервере и может обращаться к серверным методам (с директивами &НаСервере или &НаСервереБезКонтекста). Однако серверный контекст ничего не знает о клиентском окружении. Вызов процедуры с директивой &НаКлиенте из серверного метода невозможен, так как при компиляции серверного блока модуля клиентские методы просто отсутствуют в таблице доступных серверу процедур и функций.
  2. Ограничение типов данных на клиенте. Объект типа ТаблицаЗначений не существует в контексте тонкого или веб-клиента. Даже если бы вызов клиентской процедуры был возможен, передача переменной Тз на клиент привела бы к ошибке выполнения из-за невозможности сериализации этого типа данных.
  3. Работа с макетами. Метод получения макета объекта метаданных или отчета доступен исключительно на стороне сервера. Получать макет на клиенте через дополнительный серверный вызов не имеет практического смысла, если исходные данные уже сформированы на сервере.

Способ 1. Полное формирование отчета на сервере (рекомендуемый)

Рассмотрим основной и наиболее производительный подход. Формирование таблицы значений, получение макета, вывод областей и заполнение результирующего табличного документа должны выполняться в едином серверном контексте.

В этом случае клиент лишь инициирует команду формирования, а вся тяжелая обработка и вывод данных происходят на сервере без лишних вызовов между клиентом и сервером:


&НаКлиенте
Процедура Сформировать(Команда)
    СформироватьНаСервере();
КонецПроцедуры

&НаСервере
Процедура СформироватьНаСервере()
    Тз = СоздатьТЗ();
    
    Если ЗначениеЗаполнено(Тз) И Тз.Количество() > 0 Тогда
        ВывестиТзВМакет(Тз);
    Иначе
        Сообщить("Нет данных для выборки!");
    КонецЕсли;
КонецПроцедуры

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

Способ 2. Передача данных через временное хранилище

Если логика формы требует разделения получения данных и их последующего интерактивного использования на клиенте, таблицу значений нельзя передавать напрямую. Разберем, как сохранить серверные данные и вернуть на клиент строковый адрес:

  1. На сервере формируем таблицу значений и помещаем ее во временное хранилище с помощью функции ПоместитьВоВременноеХранилище.
  2. Возвращаем уникальный адрес (URL) на клиент.
  3. При необходимости дальнейшей обработки на клиенте оперируем адресом хранилища или преобразуем данные в клиентские типы (например, в массив структур через Массив и Структура).

Посмотрим на пример реализации передачи адреса:


&НаКлиенте
Процедура СформироватьИОбработать(Команда)
    АдресХранилища = "";
    СформироватьДанныеНаСервере(АдресХранилища);
    
    Если ЗначениеЗаполнено(АдресХранилища) Тогда
        // Передаем адрес в другую серверную процедуру для дальнейшей работы
        ВывестиДанныеИзХранилищаНаСервере(АдресХранилища);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура СформироватьДанныеНаСервере(АдресХранилища)
    Тз = СоздатьТЗ();
    // Помещаем таблицу значений во временное хранилище текущей формы
    АдресХранилища = ПоместитьВоВременноеХранилище(Тз, УникальныйИдентификатор);
КонецПроцедуры

Рекомендации по оптимизации

Для повышения производительности управляемой формы обратите внимание на следующие правила:

  1. Минимизируйте контекстные серверные вызовы. Если процедуре не требуются реквизиты самой формы, используйте директиву &НаСервереБезКонтекста. Это исключает передачу состояния формы по сети между клиентом и сервером.
  2. Избегайте избыточных переключений контекста. Не вызывайте серверные методы в циклах на клиенте. Вся логика обработки массивов данных и формирования документов должна быть инкапсулирована в одном серверном вызове.
← На главную