Передача данных между управляемыми формами

05 апреля 2013

Конфигурация с примером

Поставленная задача

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

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

Реализация

Для демонстрации двух вариантов передачи данных между управляемыми формами реализуем оба варианта в подборе.

Без обращения к серверу

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

Создадим форму списка у справочника "Товары". При этом не назначим ее основной. В реквизиты формы добавим таблицу "ПодобранныеТовары" и разместим соответствующий элемент формы. При этом для полей динамического списка "ЭтоГруппа" и "Ссылка" установим флаг "Использовать всегда". Далее Вы увидите для чего.

Теперь нам нужно написать программный код обработки выбора в динамическом списке. Все действия выбора будут сводитсья к добавлению строки в таблицу "Подобранные товары" элементов справочника. Если элемент уже был добавлен в таблицу, то увеличиваем его количество. Программный код обработки выбора (событие "Выбор") списка номенклатуры приведен на следующем листинге:

&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)      	
	// Проверка на наличие выбранной строки в списке
	ТекДанные = Элементы.Список.ТекущиеДанные;
	Если ТекДанные = Неопределено Тогда Возврат; КонецЕсли;   	
	// Для групп номенклатуры подбор не производится. Именно для обращения
	// к свойству "ЭтоГруппа" бил установлен флаг "Использовать всегда", иначе
	// при отсутствии колонки "Это группа" в списке вылетала бы ошибка "Поле объекта не найдено"
	Если ТекДанные.ЭтоГруппа Тогда Возврат; КонецЕсли;
	// Отключаем стандартную обработку
	СтандартнаяОбработка = Ложь;
	// Ищем товар в таблице "Подобранные товары". Если нет - добавляем строку, иначе добавляем количество
	РезультатПоиска = ПодобранныеТовары.НайтиСтроки(Новый Структура("Товар", ТекДанные.Ссылка));
	Если РезультатПоиска.Количество() = 0 Тогда
		Стр = ПодобранныеТовары.Добавить();
		Стр.Товар = ТекДанные.Ссылка;
	Иначе
		Стр = РезультатПоиска[0];
	КонецЕсли;
	Стр.Количество = Стр.Количество + 1;  	
КонецПроцедуры

Форма подбора товаров вызывается из формы документа по команде "Подбор".

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

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

Когда в форме выбора необходимые товары подобраны выполняется команда "ПеренестиВДокументКлиент". Обработчик события очень простой:

&НаКлиенте
Процедура ПеренестиВДокументКлиент(Команда)
	// Передаем в родительский элемент формы "Товары" данные выбора - таблицу "Подобранные товары"
	ОповеститьОВыборе(ПодобранныеТовары);      	
КонецПроцедуры

После выполнения метода "ОповеститьОВыборе" данные передаются в обработчик "ОбработкаВыбора" элемента формы документа "Товары", и далее обрабатывается:

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

В результате таблица товаров документа будет заполнена. При использвовании этого варианта передачи данных между формами не было произведено вызовов к серверу. Однако у подобного подхода есть несколько больших минусов:

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

С обращением к серверу

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

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

Теперь алгоритм обработки выбора элемента формы документа "Товары" изменится следующим образом:

&НаКлиенте
Процедура ТоварыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)     	
	// Обрабатываем значение выбора на сервере
	ОбработкатьВыбранноеЗначение(ВыбранноеЗначение);    		
КонецПроцедуры
&НаСервере
Процедура ОбработкатьВыбранноеЗначение(ВыбранноеЗначение)
	// Получаем таблицу подобранных товаров на сервере
	ТаблицаПодобранныхТоваров = ПолучитьИзВременногоХранилища(ВыбранноеЗначение);
	// Переносим в таблицу "Товары" подобранные элементы
	Для Каждого Стр Из ТаблицаПодобранныхТоваров Цикл
		РезультатПоиска = Объект.Товары.НайтиСтроки(Новый Структура("Товар", Стр.Товар));
		Если РезультатПоиска.Количество() = 0 Тогда
			НовСтр = Объект.Товары.Добавить();
			НовСтр.Товар = Стр.Товар;
		Иначе
			НовСтр = РезультатПоиска[0];	
		КонецЕсли;
		НовСтр.Количество = НовСтр.Количество + Стр.Количество;
	КонецЦикла;	
КонецПроцедуры

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

Вместо выводов

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


comments powered by Disqus