Как получить и редактировать объект по ссылке на управляемой форме 1С

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача создания интерфейса типа "Мастер-Деталь" или "Дашборд". В таких случаях на одной форме располагается список документов или справочников, а рядом — блок для быстрого просмотра и редактирования выбранного элемента. Основная сложность заключается в том, что в управляемом приложении работа с типами ДокументОбъект или СправочникОбъект возможна только на сервере, а передать их "как есть" на клиент нельзя. Разберем детально, как правильно реализовать получение объекта по ссылке и его отображение в блоке редактирования.

Анализ проблемы: почему стандартный подход не работает

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

Проанализируем типичную ошибку начинающего разработчика:


&НаСервере
Функция _ПолучитьОбъект(_Ссылка)
    Возврат _Ссылка.ПолучитьОбъект(); // Объект нельзя вернуть на клиент!
КонецФункции

При выполнении этого кода система выдаст сообщение: "Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа". Это происходит потому, что объект данных (например, ДокументОбъект.РеализацияТоваровУслуг) не является сериализуемым для передачи между программными слоями. Он предназначен для выполнения серверных операций (запись, проведение, проверка заполнения) и не может существовать в памяти клиентского приложения.

Решение задачи с использованием реквизитов формы

Для того чтобы данные объекта стали доступны на форме для редактирования, необходимо использовать механизм соответствия между объектом базы данных и реквизитом управляемой формы. Основным инструментом здесь выступает метод ЗначениеВРеквизитФормы.

Разберем по шагам, как настроить форму:

  1. Создадим на форме реквизит (например, с именем ДокументРедактирования). В колонке "Тип" выберем тип нужного документа, но укажем не ссылку, а именно ДокументОбъект.
  2. Разместим поля этого реквизита на форме (перетащим их в нужную группу элементов).
  3. Напишем серверную процедуру для загрузки данных в этот реквизит.

Рассмотрим правильный программный код для реализации этой задачи:


&НаСервере
Процедура ЗагрузитьОбъектНаФорму(ВыбраннаяСсылка)
    
    // Получаем объект из ссылки
    ОбъектБД = ВыбраннаяСсылка.ПолучитьОбъект();
    
    // Копируем данные из объекта в реквизит формы
    // "ДокументРедактирования" — это имя реквизита формы с типом ДокументОбъект
    ЗначениеВРеквизитФормы(ОбъектБД, "ДокументРедактирования");
    
КонецПроцедуры

Этот метод работает эффективно, так как платформа сама берет на себя задачу по "распаковке" данных объекта в структуру реквизитов формы, которые уже доступны на клиенте для отображения и ввода пользователем.

Сохранение изменений обратно в базу данных

После того как пользователь отредактировал данные в блоке, их необходимо сохранить. Процесс обратный: нам нужно преобразовать данные из реквизита формы в объект, а затем вызвать метод Записать(). Проанализируем пример реализации сохранения:


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

Оптимизация работы при активации строки

Если вы вызываете загрузку объекта в событии ПриАктивацииСтроки, важно помнить о производительности. При быстром пролистывании списка пользователем сервер будет перегружен запросами на получение объектов. Чтобы избежать "тормозов" интерфейса, рекомендуется использовать следующий прием:

Проанализируем алгоритм с использованием обработчика ожидания:


&НаКлиенте
Процедура СписокПриАктивацииСтроки(Элемент)
    // Отключаем предыдущий вызов, если пользователь нажал кнопку быстро
    ОтключитьОбработчикОжидания("ИсполнитьЗагрузкуОбъекта");
    // Запускаем загрузку с задержкой в 0.3 - 0.5 секунды
    ПодключитьОбработчикОжидания("ИсполнитьЗагрузкуОбъекта", 0.3, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ИсполнитьЗагрузкуОбъекта()
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ЗагрузитьОбъектНаФорму(ТекущиеДанные.Ссылка);
    КонецЕсли;
КонецПроцедуры

Такой подход делает интерфейс отзывчивым, так как серверные вызовы происходят только тогда, когда пользователь остановился на конкретной строке.

Альтернативный метод: Частичное редактирование

Иногда нет смысла загружать весь ДокументОбъект (со всеми его табличными частями и десятками реквизитов), если в блоке редактирования нужно поменять только пару полей (например, "Статус" или "Комментарий"). В этом случае выгоднее создать на форме простые реквизиты (строковые, числовые) и заполнять их напрямую из ссылки.

Рассмотрим пример частичного обновления:


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

&НаСервере
Процедура СохранитьТолькоНужныеПоля(Ссылка)
    Объект = Ссылка.ПолучитьОбъект();
    Объект.Статус = ЭлементСтатус;
    Объект.Комментарий = ЭлементКомментарий;
    Объект.Записать();
КонецПроцедуры

Важно: При использовании метода ЗначениеВРеквизитФормы платформа автоматически отслеживает Модифицированность формы. Если вы меняете данные в блоке редактирования, форма "поймет", что она изменена, и предложит сохранить данные при закрытии.

Создание новых объектов в том же блоке

Если ваша задача подразумевает и создание новых документов в этом же интерфейсе, то на сервере следует использовать метод СоздатьДокумент(). Выясним, как это выглядит в коде:


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

В этом случае в реквизите ДокументРедактирования окажется объект с пустой ссылкой. При сохранении (через РеквизитФормыВЗначение и Записать) ссылка будет создана, и вы сможете обновить список (таблицу) на основной форме, чтобы новый документ там появился.

Подводя итог, можно сказать, что работа с объектами по ссылке в управляемых формах требует четкого понимания разделения между данными базы (объектами) и данными интерфейса (реквизитами формы). Использование ЗначениеВРеквизитФормы является наиболее универсальным и быстрым способом реализовать "вложенное" редактирование без открытия лишних окон.

← На главную