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

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

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

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

Разберем проблему: почему результат оказывается «Неопределено»

Рассмотрим ситуацию, с которой столкнулся автор темы. При использовании метода ОткрытьФорму с параметром ОписаниеОповещения, ожидается, что после закрытия формы справочника в процедуру-обработчик придет результат. Однако, если пользователь нажимает стандартную системную кнопку «Записать и закрыть», параметр Результат в оповещении всегда будет равен Неопределено.

Это происходит потому, что стандартная команда закрытия формы просто завершает работу окна, не зная, какое именно значение нужно вернуть вызывающей стороне. Чтобы передать ссылку (или любое другое значение), форму необходимо закрыть программно, явно передав параметр в метод Закрыть().

Решение 1: Использование программного закрытия формы с возвратом ссылки

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

Шаг 1. Настройка формы документа

В форме документа (например, «Акт приемки») создадим процедуру для открытия формы справочника. Мы будем использовать ОписаниеОповещения, чтобы указать системе, какой код выполнить после того, как справочник будет закрыт.


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

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

Шаг 2. Доработка формы справочника

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


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

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

Решение 2: Использование стандартного режима выбора

Если нам не хочется писать много кода в форме справочника, можно воспользоваться стандартным механизмом выбора платформы 1С. Для этого в параметрах открытия формы нужно указать РежимВыбора = Истина.

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

  1. В форме документа при вызове ОткрытьФорму передаем параметр РежимВыбора = Истина.
  2. В качестве владельца указываем не саму форму, а конкретный элемент управления (например, поле ввода товара в табличной части).

&НаКлиенте
Процедура СоздатьТоварРежимВыбора(Команда)

    ПараметрыНовогоТовара = Новый Структура;
    ПараметрыНовогоТовара.Вставить("РежимВыбора", Истина);
    
    // Указываем владельцем элемент формы - поле в ТЧ
    // ВАЖНО: ТЧ должна быть в режиме редактирования
    Элементы.Товары.ИзменитьСтроку(); 
    ВладелецПоля = Элементы.ТоварыТовар; // Конкретное поле в колонке
    
    ОткрытьФорму("Справочник.Товары.ФормаОбъекта", ПараметрыНовогоТовара, ВладелецПоля);

КонецПроцедуры

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

Решение 3: Глобальные оповещения (метод Оповестить)

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

В форме справочника:


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

В форме документа:


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

Сводная таблица методов

Выясним, какой метод лучше выбрать в зависимости от условий задачи:

  1. ОписаниеОповещения + Закрыть(Ссылка) — Идеально для разового создания объекта с возвратом управления в конкретную процедуру. Требует вмешательства в код формы справочника.
  2. РежимВыбора = Истина — Стандартный путь. Хорошо работает, если нужно просто заполнить поле. Минус: сложно передать дополнительные данные, кроме самой ссылки.
  3. ОбработкаОповещения — Лучший вариант, если формы живут «своей жизнью» и не связаны жестко иерархией «Владелец-Дочерняя форма».

Рекомендации по работе с табличными частями

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

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

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

← На главную