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

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

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

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

Почему возникает ошибка при попытке передать таблицу значений напрямую

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


&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
    Закрыть(ПередЗакрытиемС());
КонецПроцедуры

Такой код приводит к ошибкам по двум причинам:

  1. Недоступность типа на клиенте: Объект ТаблицаЗначений не существует в контексте тонкого клиента и не может быть автоматически сериализован при вызове с сервера.
  2. Зацикливание закрытия: Вызов метода Закрыть() непосредственно внутри клиентского события ПередЗакрытием может вызвать некорректное поведение формы или рекурсию.

Способ 1. Использование временного хранилища и механизма выбора (рекомендуемый для больших таблиц)

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

Шаг 1. Открытие формы подбора в документе

В форме документа открываем форму обработки или списка, обязательно передавая текущую форму в качестве владельца:


&НаКлиенте
Процедура Подбор(Команда)
    ПараметрыФормы = Новый Структура;
    ОткрытьФорму("Обработка.ПодборТоваров.Форма.ПодборТоваров", ПараметрыФормы, ЭтаФорма);
КонецПроцедуры

Шаг 2. Сохранение данных и оповещение в форме подбора

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


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

&НаКлиенте
Процедура ЗавершитьПодбор(Команда)
    АдресВХранилище = ПоместитьДанныеВоВременноеХранилище();
    
    СтруктураОповещения = Новый Структура;
    СтруктураОповещения.Вставить("АдресПодобранныхДанных", АдресВХранилище);
    
    // Передаем данные владельцу и закрываем форму
    ОповеститьОВыборе(СтруктураОповещения);
КонецПроцедуры

Шаг 3. Прием данных в форме документа

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


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

&НаСервере
Процедура ОбработатьПодборНоменклатуры(АдресПодобранныхДанных)
    ТаблицаПодбора = ПолучитьИзВременногоХранилища(АдресПодобранныхДанных);
    
    // Удаляем данные из хранилища после прочтения для освобождения памяти
    УдалитьИзВременногоХранилища(АдресПодобранныхДанных);
    
    Для Каждого Стр Из ТаблицаПодбора Цикл
        НоваяСтрока = Объект.Товары.Добавить();
        НоваяСтрока.Номенклатура = Стр.Номенклатура;
        НоваяСтрока.Количество = Стр.Количество;
    КонецЦикла;
КонецПроцедуры

Способ 2. Сериализация в массив структур через ОписаниеОповещения

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

Разберем реализацию этого варианта:


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

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

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

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


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

&НаКлиенте
Процедура КнопкаПеренестиВДокумент(Команда)
    Результат = СформироватьМассивСтруктур();
    Закрыть(Результат);
КонецПроцедуры

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

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

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

Таким образом, для переноса данных между формами на управляемом интерфейсе следует использовать сериализуемые на клиенте коллекции (массивы структур), механизм выбора формы через временное хранилище с привязкой к владельцу, либо события оповещения.

← На главную