Почему не переносятся данные из формы подбора в документ 1С и как это исправить?

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

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

Выясним причину проблемы

В тонком клиенте и управляемом приложении каждая форма имеет свой собственный изолированный контекст данных (тип ДанныеФормыСтруктура). В описанной ситуации при обращении к реквизиту Объект внутри серверной процедуры формы подбора измеряются данные самой формы подбора, а не вызвавшего ее документа.

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

Способ 1. Использование механизма оповещений (Оповестить и ОбработкаОповещения)

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

Разберем по шагам реализацию в форме подбора:

  1. На клиенте формируем структуру с выбранными параметрами.
  2. Вызываем метод Оповестить() и закрываем форму подбора.

Посмотрим на пример кода для формы подбора:


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

Теперь перейдем в форму основного документа и обработаем полученное событие:


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

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

Способ 2. Использование ОписаниеОповещенияОЗакрытии

Если требуется передать данные непосредственно в вызвавшую процедуру без генерации общего события в системе, разберем использование параметров закрытия формы и объекта ОписаниеОповещения.

В форме основного документа открываем форму подбора с указанием обработчика оповещения о закрытии:


&НаКлиенте
Процедура Подобрать(Команда)
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораВФормеПодбора", ЭтаФорма);
    ОткрытьФорму("Документ.ЛМБ_СкупкаЦенностей.Форма.ФормаПодбораВещи", , ЭтаФорма, , , , ОписаниеОповещения);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораВФормеПодбора(РезультатВыбора, ДополнительныеПараметры) Экспорт
    Если ЗначениеЗаполнено(РезультатВыбора) Тогда
        ЗаполнитьДокументПоБилетуНаСервере(РезультатВыбора);
    КонецЕсли;
КонецПроцедуры

В форме подбора передаем выбранные данные непосредственно в метод Закрыть():


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

Важные технические нюансы

При работе с управляемыми формами обратим внимание на следующие критические моменты:

  1. Обращение к элементам формы: Конструкция ЭтаФорма.ТекущийЭлемент.ТекущиеДанные небезопасна, так как зависит от того, какой именно элемент UI находится в фокусе ввода. Следует обращаться к конкретному элементу таблицы напрямую через коллекцию Элементы, например: Элементы.ИмяТаблицы.ТекущиеДанные.
  2. Проверка на Неопределено: Перед обращением к свойствам строки списка обязательна проверка Если ТекДанные <> Неопределено Тогда, иначе при открытии с пустым списком платформа выдаст ошибку обращения к значению типа Неопределено.
  3. Отказ от синхронных вызовов: Функция Вопрос() блокирует поток выполнения и не работает в асинхронном режиме (например, в веб-клиенте). Для запроса подтверждения у пользователя рекомендуем использовать метод ПоказатьВопрос() с передачей процедур-обработчиков через ОписаниеОповещения.
← На главную