Как открыть форму обработки или документа и показать данные табличной части или реквизитов?

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

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

Основные подходы к передаче данных при открытии формы

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

  1. Прямое копирование данных объекта в объект формы. Этот метод особенно полезен, когда нам необходимо полностью инициализировать объект основной формы данными из другого объекта.
  2. Присвоение значений отдельным реквизитам формы. Если требуется передать лишь несколько конкретных реквизитов, этот подход может быть более точечным.
  3. Передача параметров через структуру ПараметрыОткрытия и их обработка в процедуре ПриСозданииНаСервере. Это наиболее гибкий и рекомендуемый подход в управляемом приложении, позволяющий тонко настраивать процесс инициализации формы.

Давайте разберем каждый из этих методов подробнее.

1. Прямое копирование данных объекта в объект формы

Этот способ позволяет передать все данные объекта (или его части) в основной реквизит открываемой формы. Это особенно актуально для обработок, когда форма обработки содержит основной реквизит типа ОбработкаОбъект.<ИмяОбработки>.

Ситуация: У нас есть существующий объект обработки (или документа), и мы хотим открыть новую форму обработки (или документа), в которой сразу будут отображены все данные этого объекта, включая табличные части.

Пример кода для вызывающей стороны:


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

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

    // ... здесь заполняем ОбъектДляПередачи данными, например, его табличную часть
    // ОбъектДляПередачи.МояТабличнаяЧасть.Добавить().Поле1 = "Значение1";
    // ОбъектДляПередачи.МояТабличнаяЧасть.Добавить().Поле1 = "Значение2";

    ФормаДляОткрытия = ОткрытьФормуОбработкиСДаннымиНаСервере("МояОбработка", ОбъектДляПередачи);
    ФормаДляОткрытия.Открыть(); // Открываем форму, полученную с сервера
КонецПроцедуры

Объяснение:

  1. Метод ПолучитьФорму() возвращает экземпляр формы, не открывая ее сразу. Это позволяет нам выполнить предварительные действия с формой.
  2. Ключевым моментом является функция КопироватьДанныеФормы(). Она предназначена для копирования данных между объектами ДанныеФормы. В нашем случае мы копируем данные из ОбъектИсточник (который может быть как объектом базы данных, так и программно созданным объектом) в основной реквизит формы Форма.Объект. Это обеспечивает, что все реквизиты и табличные части объекта будут перенесены в форму.
  3. После копирования данных, мы вызываем метод Форма.Открыть(), чтобы отобразить форму пользователю.

Этот подход хорошо работает, когда структура данных открываемой формы совпадает со структурой передаваемого объекта. Например, если основная форма обработки имеет реквизит типа ОбъектОбработки.<ИмяОбработки>, а мы передаем объект именно этого типа.

2. Присвоение значений отдельным реквизитам формы

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

Ситуация: Нужно открыть форму документа и установить значение одного из его реквизитов, например, для фильтрации данных или предзаполнения.

Пример кода для вызывающей стороны:


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

Объяснение:

  1. Как и в предыдущем случае, мы используем ПолучитьФорму() для получения экземпляра формы.
  2. После получения формы мы можем обратиться к ее реквизитам (или к реквизитам ее основного объекта) и установить нужные значения.
  3. Метод МояФорма.Открыть() отображает форму пользователю с уже установленными данными.

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

3. Рекомендуемый подход: Передача параметров через ПараметрыОткрытия и обработка в ПриСозданииНаСервере

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

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

Пример кода для вызывающей стороны:


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

    // 2. Открываем форму, передавая структуру с параметрами.
    // Имя формы указываем полностью: "ВидОбъекта.ИмяОбъекта.Форма.ИмяФормы".
    ОткрытьФорму("Обработка.МояОбработка.Форма.ФормаСТабличнойЧастью", ПараметрыДляФормы);
    
    // Для документов:
    // ОткрытьФорму("Документ.СвойДокумент.Форма.ФормаТЧ", ПараметрыДляФормы);
КонецПроцедуры

Пример кода для открываемой формы (в модуле формы, процедура ПриСозданииНаСервере):


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

        КонецЕсли;
    КонецЕсли;
    
    // 3. Обрабатываем другие переданные параметры.
    Если Параметры.Свойство("ДополнительныйПараметр") Тогда
        ЗначениеДополнительногоПараметра = Параметры.ДополнительныйПараметр;
        // Используем его для инициализации других реквизитов формы
        // Например, РеквизитФормы1 = ЗначениеДополнительногоПараметра;
    КонецЕсли;

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

Объяснение:

  1. Передача параметров: Метод ОткрытьФорму() позволяет передать вторым аргументом структуру ПараметрыОткрытия. Эта структура может содержать любые данные, которые вы хотите передать в новую форму. Рекомендуется использовать ключ "Ключ" для ссылки на основной объект, который должна открыть форма (например, ДокументСсылка или ОбработкаСсылка).
  2. Обработка в ПриСозданииНаСервере: В открываемой форме эти параметры становятся доступны в коллекции Параметры в процедуре ПриСозданииНаСервере. Эта процедура выполняется на сервере в момент создания экземпляра формы.
  3. Загрузка данных: В этой процедуре мы проверяем наличие переданных параметров и используем их для инициализации реквизитов формы, включая основной объект формы и ее табличные части. Для документов, получив ссылку, мы можем получить объект документа методом ПолучитьОбъект() и скопировать его данные в основной реквизит формы с помощью КопироватьДанныеФормы(). Для обработок, если основной реквизит формы не является объектом, связанным с БД, мы можем вручную заполнить его реквизиты и табличные части, используя данные, переданные в Параметры.
  4. Явное объявление параметров формы: Для повышения читаемости и контроля, параметры формы можно явно объявить на закладке "Параметры" редактора формы. Это позволяет платформе автоматически проверять наличие и типы параметров, а также делает их доступными как свойства объекта Параметры без дополнительной проверки на наличие свойства.
  5. Ключевые и обычные параметры: Ключевые параметры (например, Ключ, который часто содержит ссылку на объект) влияют на уникальность формы (предотвращая открытие нескольких одинаковых форм для одного и того же объекта) и сохраняются на протяжении всей жизни формы. Обычные параметры существуют только в момент создания формы. Если обычные параметры необходимы для дальнейшей работы формы, их следует сохранить в реквизитах формы.

Этот подход обеспечивает наилучшую архитектуру, разделяя логику вызова формы от логики ее инициализации, и делает код более поддерживаемым.

Заполнение табличной части объекта формы с помощью запроса

Часто данные для табличной части нужно не просто передать, а загрузить из базы данных на основе переданных параметров. Это можно сделать также в процедуре ПриСозданииНаСервере.

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

Пример кода в открываемой форме (в модуле формы, процедура ПриСозданииНаСервере):


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("ДокументОснование") Тогда
        СсылкаНаДокумент = Параметры.ДокументОснование;

        // Очищаем существующую табличную часть формы, если она уже содержит данные
        Объект.ТабличнаяЧастьФормы.Очистить(); // Объект - основной реквизит формы, ТабличнаяЧастьФормы - его реквизит

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

Объяснение:

  1. Мы получаем ссылку на документ-основание из переданных параметров.
  2. Затем выполняем запрос к базе данных, чтобы выбрать необходимые данные из табличной части этого документа. Запрос позволяет нам выполнить фильтрацию, агрегацию или любые другие необходимые преобразования данных.
  3. Результат запроса (обычно это ТаблицаЗначений) итерируется, и для каждой строки результата создается новая строка в табличной части формы, которая затем заполняется соответствующими значениями.

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

Различия между методами ОткрытьФорму() и ПолучитьФорму()

На форуме часто обсуждается разница между этими двумя методами, и важно понимать, когда какой использовать.

Метод ОткрытьФорму():

  1. Назначение: Основной метод для открытия формы и немедленного ее отображения пользователю.
  2. Параметры: Позволяет передать структуру ПараметрыОткрытия для инициализации формы.
  3. Асинхронность: В управляемом приложении по умолчанию работает асинхронно (не модально). Код, следующий за вызовом ОткрытьФорму(), продолжает выполняться немедленно. Для обработки результата работы с формой (например, выбора элемента) необходимо использовать механизм оповещений (ОписаниеОповещения).
  4. Эффективность: Зачастую более эффективен, так как может выполнить меньшее количество серверных вызовов по сравнению с комбинацией ПолучитьФорму() + Открыть().

Метод ПолучитьФорму():

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

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

Модальные и немодальные окна: ОткрытьМодально() против Открыть() / ОткрытьФорму()

Понимание отличий между модальным и немодальным открытием форм критически важно для корректной работы приложения и обеспечения удобства пользователя.

Форма.ОткрытьМодально():

  1. Поведение: Открывает форму как модальное окно. Это означает, что работа с остальным интерфейсом приложения блокируется до тех пор, пока модальное окно не будет закрыто.
  2. Возврат значения: Код, вызвавший ОткрытьМодально(), приостанавливается до закрытия модального окна и получает возвращаемое значение (если оно было задано в закрываемой форме методом Закрыть(Значение)).
  3. Совместимость: Широко использовался в предыдущих версиях платформы (например, 8.2, 8.1), что отражено в некоторых старых примерах кода.
  4. Ограничения в веб-клиенте: В веб-клиенте ОткрытьМодально() может привести к открытию нового всплывающего окна браузера, которое может быть заблокировано браузером как "всплывающее", или которое блокирует весь интерфейс браузера. Это негативно сказывается на пользовательском опыте.

Форма.Открыть() (после ПолучитьФорму()) и ОткрытьФорму():

  1. Поведение: Открывает форму как немодальное (или блокирующее) окно. Это означает, что пользователь может взаимодействовать с другими элементами интерфейса приложения, пока открытая форма активна.
  2. Асинхронность: Код, вызвавший открытие формы, продолжает выполняться немедленно, не дожидаясь закрытия формы.
  3. Обработка результата: Для получения результата работы с формой (например, выбранных данных) необходимо использовать механизм оповещений (ОписаниеОповещения), который позволяет выполнить код после закрытия формы или после выполнения определенного действия в ней.
  4. Рекомендация: В 1С:Предприятии 8.3 существует общая тенденция к отказу от модальных окон в пользу немодальных, особенно для обеспечения лучшей кросс-платформенной работы (например, в веб-клиенте) и более гибкого пользовательского интерфейса.

Мы рекомендуем использовать немодальные подходы (ОткрытьФорму() или ПолучитьФорму() с последующим Открыть()) и механизм оповещений для обработки результатов. Метод ОткрытьМодально() следует применять только в случаях, когда это строго необходимо для сохранения логики работы или совместимости с очень старым кодом, и при этом необходимо учитывать его ограничения в веб-клиенте.

Заключение

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

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

← На главную