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