При разработке интерфейсов в среде 1С:Предприятие 8.3 часто возникает задача повышения эргономики работы пользователя. Одной из таких задач является редактирование данных связанного объекта (например, справочника «Модели») непосредственно в карточке владельца (например, справочника «Автомобили»). По умолчанию платформа позволяет выводить данные связанных объектов через «путь к данным» (Объект.Модель.Наименование), но такие поля доступны только для чтения. В этой статье мы подробно разберем, как обойти это ограничение и реализовать полноценное редактирование.
Когда мы указываем в пути к данным элемента формы путь через точку (например, Объект.СсылкаНаСправочник.НужныйРеквизит), система обращается к данным через ссылку. Ссылочные данные в управляемых формах защищены от прямого изменения для обеспечения целостности данных. Чтобы редактировать объект, нам необходимо получить его в память сервера как СправочникОбъект, изменить его и вызвать метод Записать(). Мы рассмотрим наиболее эффективный способ реализации этого механизма через реквизиты формы.
Для начала проанализируем ситуацию: нам нужно иметь доступ к данным другого справочника в контексте текущей формы. Создавать 20-30 отдельных реквизитов для каждого поля «Модели» нецелесообразно. Правильным подходом будет создание одного реквизита формы, который будет содержать весь объект целиком.
ДанныеМодели.СправочникОбъект.Модели (вместо привычной ссылки).Важный момент: Реквизиты формы с типом СправочникОбъект позволяют напрямую связывать свои поля с элементами формы (полями ввода), и эти поля будут доступны для редактирования.
Теперь выясним, как «пробросить» данные из существующей ссылки в наш новый реквизит формы. Для этого используются методы платформы ЗначениеВРеквизитФормы и РеквизитФормыВЗначение. Разберем программный код, который необходимо разместить в модуле формы.
Нам понадобится серверная процедура, вызываемая при создании или чтении данных:
&НаСервере
Процедура ЗаполнитьДанныеСвязанногоСправочникаНаСервере()
// Проверяем, заполнена ли ссылка на модель в основном объекте
Если ЗначениеЗаполнено(Объект.Модель) Тогда
// Получаем объект справочника по ссылке
ОбъектМодели = Объект.Модель.ПолучитьОбъект();
// Копируем данные объекта в реквизит формы
// "ДанныеМодели" — это имя нашего реквизита формы с типом СправочникОбъект
ЗначениеВРеквизитФормы(ОбъектМодели, "ДанныеМодели");
КонецЕсли;
КонецПроцедуры
Эту процедуру следует вызывать в стандартных обработчиках ПриСозданииНаСервере или ПриЧтенииНаСервере, чтобы при открытии карточки пользователя поля сразу заполнялись актуальными данными.
Просто изменить данные на форме недостаточно — их нужно записать в базу данных. Проанализируем, где это лучше сделать. Оптимальным местом является обработчик ПередЗаписьюНаСервере основной формы. Это гарантирует, что и автомобиль, и его модель будут сохранены (или отклонены) в рамках одной транзакции.
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Преобразуем данные из реквизита формы обратно в объект прикладного решения
ОбъектМоделиДляЗаписи = РеквизитФормыВЗначение("ДанныеМодели", Тип("СправочникОбъект.Модели"));
Попытка
// Записываем изменения в справочник моделей
ОбъектМоделиДляЗаписи.Записать();
Исключение
// Если возникла ошибка (например, нарушение прав или блокировка), отменяем запись основного объекта
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось сохранить данные модели: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке());
Сообщение.Сообщить();
Отказ = Истина;
КонецПопытки;
КонецПроцедуры
Рассмотрим ситуацию: пользователь решил выбрать в карточке автомобиля другую модель. В этот момент данные в наших дополнительных полях станут неактуальными, так как они все еще хранят информацию о «старой» модели. Нам необходимо реализовать обновление. Для этого создадим обработчик события ПриИзменении для поля Объект.Модель.
&НаКлиенте
Процедура МодельПриИзменении(Элемент)
// Вызываем серверную процедуру для обновления данных формы
ОбновитьДанныеМоделиНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОбновитьДанныеМоделиНаСервере()
// Повторяем логику заполнения реквизита формы из Шага 2
Если ЗначениеЗаполнено(Объект.Модель) Тогда
ЗначениеВРеквизитФормы(Объект.Модель.ПолучитьОбъект(), "ДанныеМодели");
Иначе
// Если модель очищена, очищаем и реквизит формы
// Создаем пустой объект нужного типа
ПустойОбъект = Справочники.Модели.СоздатьЭлемент();
ЗначениеВРеквизитФормы(ПустойОбъект, "ДанныеМодели");
КонецЕсли;
КонецПроцедуры
Реализуя подобный механизм, мы должны помнить о нескольких критически важных моментах, которые могут повлиять на стабильность системы:
СправочникОбъект, при записи происходит блокировка записи модели. Если два пользователя одновременно редактируют разные автомобили одной и той же модели, один из них может получить ошибку блокировки при попытке записи.Записать() вызовет исключение.ПриСозданииНаСервере.Использование реквизита формы с типом СправочникОбъект — это мощный и относительно простой способ создания сложных интерфейсов «всё в одном». Мы рассмотрели полный цикл: от создания реквизита до обработки транзакционной записи. Применяйте этот метод осторожно, учитывая бизнес-логику вашего приложения.