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