Как передать данные из табличной части в серверную функцию и исправить ошибку «ПолеФормы»

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

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

Разбор причины возникновения ошибки

Проанализируем ситуацию, представленную в вопросе. Автор пытается вызвать функцию ПолучитьДанныеНормаВремени на сервере, передавая в неё два параметра. Давайте посмотрим на фрагмент клиентского кода:


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

Здесь кроется ключевая ошибка: в качестве второго параметра передается Элементы.Автомобиль. В управляемом приложении коллекция Элементы содержит объекты интерфейса (кнопки, поля ввода, таблицы), которые существуют исключительно на стороне тонкого или веб-клиента. Сервер «не знает», что такое поле ввода на форме, он работает только с данными. Когда платформа пытается передать визуальный объект ПолеФормы через границу «клиент-сервер», происходит сбой сериализации, и мы получаем ту самую ошибку отображения типов.

Решение №1: Передача данных из реквизита напрямую

Самый простой и правильный способ исправить ошибку — передавать не сам элемент формы, а значение реквизита, к которому этот элемент привязан. Рассмотрим исправленный код клиентской процедуры:


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

КонецПроцедуры

В данном примере Объект.Автомобиль является ссылкой (например, СправочникСсылка.Автомобили), которая легко передается на сервер, так как этот тип данных понятен обеим сторонам.

Решение №2: Использование структуры для передачи параметров

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

Разберем пример реализации через структуру:


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

    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("Услуга", СтрНормаВремени.Услуга);
    ПараметрыЗапроса.Вставить("Автомобиль", Объект.Автомобиль);
    
    СтрНормаВремени.НормаВремени = ПолучитьДанныеНормаВремени(ПараметрыЗапроса);

КонецПроцедуры

На стороне сервера функция примет следующий вид:


&НаСервереБезКонтекста
Функция ПолучитьДанныеНормаВремени(Параметры)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЕСТЬNULL(СписокУслугНормаВремени.НормВремя, 0) КАК НормаВремени
        |ИЗ
        |   Справочник.СписокУслуг.НормаВремени КАК СписокУслугНормаВремени
        |ГДЕ
        |   СписокУслугНормаВремени.Ссылка = &Услуга
        |   И СписокУслугНормаВремени.Автомобиль = &Автомобиль";
    
    Запрос.УстановитьПараметр("Автомобиль", Параметры.Автомобиль);
    Запрос.УстановитьПараметр("Услуга", Параметры.Услуга);
    
    // ... дальнейшая обработка запроса
    
КонецФункции

Проанализируем работу с контекстом формы

В исходном примере используется директива компиляции &НаСервереБезКонтекста. Это наиболее производительный вариант вызова сервера. Выясним почему:

  1. Минимальный объем данных: На сервер передаются только те параметры, которые вы явно указали (например, ссылка на автомобиль и услугу).
  2. Отсутствие передачи всей формы: При обычном вызове &НаСервере платформа упаковывает весь Объект (со всеми строками табличных частей!) и передает его на сервер, а затем возвращает обратно. Если в документе сотни строк, это создает ощутимую нагрузку на сеть и замедляет работу интерфейса.
  3. Чистота кода: Бесконтекстные функции заставляют разработчика четко определять зависимости, что упрощает отладку.

Однако помните: внутри функции &НаСервереБезКонтекста вы не можете обратиться к реквизитам формы напрямую через Объект.ИмяРеквизита. Все необходимые данные должны приходить из параметров.

Оптимизация вывода сообщений

Проанализируем еще один важный момент в коде автора — использование метода Сообщить() на сервере. Хотя 1С позволяет это делать, и сообщение «пробросится» на клиент, это не всегда удобно.

Рекомендуем возвращать результат в виде структуры, содержащей как найденное значение, так и флаг успеха или текст ошибки. Это позволит обработать результат на клиенте более гибко, например, используя ПоказатьПредупреждение() или меняя цвет поля.

Пример улучшенной обработки на сервере:


&НаСервереБезКонтекста
Функция ПолучитьДанныеНормаВремени(Услуга, Автомобиль)
    
    Результат = Новый Структура("НормаВремени, Успех", 0, Ложь);
    
    // Проверка входных данных
    Если Автомобиль.Пустая() Тогда
        Возврат Результат;
    КонецЕсли;

    Запрос = Новый Запрос("ВЫБРАТЬ ..."); // Текст запроса
    // ... установка параметров и выполнение
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        Результат.НормаВремени = Выборка.НормаВремени;
        Результат.Успех = Истина;
    КонецЕсли;
    
    Возврат Результат;
    
КонецФункции

Важные нюансы работы с ТекущиеДанные

Рассмотрим ситуацию, когда пользователь нажал на кнопку или изменил значение в пустой строке (или когда фокус не стоит на таблице). Метод Элементы.Таблица.ТекущиеДанные вернет Неопределено.

Если вы сразу обратитесь к свойству СтрНормаВремени.Услуга без проверки, система выдаст критическую ошибку «Значение не является значением объектного типа (Услуга)». Поэтому всегда используйте конструкцию:


ТекущаяСтрока = Элементы.Услуги.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
    // Работаем с данными
КонецЕсли;

Резюме

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

Соблюдение этих принципов позволит вам создавать стабильные и быстрые приложения на платформе 1С, избегая распространенных ошибок типизации и производительности.

← На главную