В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача реализации сложной логики подбора элементов. Типичный сценарий: в форме обработки или документа при выборе значения в одном поле (например, Документ2) необходимо учитывать данные, уже введенные в другом поле (например, Документ1). Если Документ2 должен присутствовать в табличной части Документа1, стандартных механизмов «Связи параметров выбора» в свойствах реквизита может быть недостаточно, особенно если между объектами нет прямой ссылки в метаданных.
В этой статье мы подробно разберем, как программно передать параметры в форму выбора, правильно настроить запрос динамического списка и избежать типичных ошибок, таких как дублирование строк или игнорирование отборов при быстром поиске.
Первым делом проанализируем ситуацию в форме, из которой инициируется выбор. Вместо того чтобы полагаться на автоматическое открытие формы платформой, мы воспользуемся событием НачалоВыбора для поля ввода или просто вызовем форму программно. Основная задача здесь — подготовить структуру параметров, которую получит форма выбора.
Рассмотрим пример кода в модуле формы обработки. Допустим, у нас есть реквизит ОбъектДляФильтрации (тот самый Документ1), и нам нужно открыть форму выбора для реквизита ВыбираемыйДокумент (Документ2):
&НаКлиенте
Процедура ВыбираемыйДокументНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Отменяем стандартное открытие формы, чтобы вызвать её программно с нашими параметрами
СтандартнаяОбработка = Ложь;
// Формируем структуру параметров для передачи в открываемую форму
ПараметрыВыбора = Новый Структура;
ПараметрыВыбора.Вставить("ДокументФильтр", Объект.ОбъектДляФильтрации);
// Указываем путь к форме выбора нужного документа
ИмяФормы = "Документ.Документ2.ФормаВыбора";
// Открываем форму, передавая структуру параметров и указывая владельца (элемент формы)
ОткрытьФорму(ИмяФормы, ПараметрыВыбора, Элемент);
КонецПроцедуры
Использование метода ОткрытьФорму позволяет нам передать любые произвольные данные, которые потребуются форме выбора для инициализации своих настроек.
Теперь перейдем к работе с формой выбора Документа2. Чтобы отбор сработал, нам нужно модифицировать текст запроса динамического списка (основного реквизита Список) и установить значение параметра, переданного из первой формы.
Проанализируем запрос динамического списка. Чтобы выбрать только те документы, которые входят в табличную часть Документа1, эффективнее всего использовать конструкцию с подзапросом или соединением. Однако, как было замечено в ходе обсуждения проблемы, простое соединение с табличной частью может привести к дублированию строк в списке, если один и тот же Документ2 встречается в таблице несколько раз.
Правильный текст запроса в схеме динамического списка должен выглядеть примерно так:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Документ2.Ссылка КАК Ссылка,
Документ2.Номер КАК Номер,
Документ2.Дата КАК Дата
ИЗ
Документ.Документ2 КАК Документ2
ГДЕ
Документ2.Ссылка В (
ВЫБРАТЬ
ТЧ.Документ2
ИЗ
Документ.Документ1.ТабличнаяЧасть1 КАК ТЧ
ГДЕ
ТЧ.Ссылка = &ПараметрДокумент1
)
ИЛИ &ПараметрДокумент1 = ЗНАЧЕНИЕ(Документ.Документ1.ПустаяСсылка)
Важные моменты:
РАЗЛИЧНЫЕ гарантирует отсутствие дублей в списке выбора.ГДЕ ... В (...) позволяет платформе оптимизировать выполнение на уровне SQL.ИЛИ &ПараметрДокумент1 = ЗНАЧЕНИЕ(...) позволяет видеть весь список, если фильтр не задан.Чтобы переданный из обработки ДокументФильтр попал в запрос динамического списка, необходимо прописать логику в обработчике ПриСозданииНаСервере формы выбора.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, передан ли наш параметр в структуре "Параметры"
Если Параметры.Свойство("ДокументФильтр") И ЗначениеЗаполнено(Параметры.ДокументФильтр) Тогда
// Устанавливаем значение параметра в динамический список
Список.Параметры.УстановитьЗначениеПараметра("ПараметрДокумент1", Параметры.ДокументФильтр);
Иначе
// Если параметр не передан, устанавливаем пустую ссылку, чтобы условие "ИЛИ" в запросе сработало
Список.Параметры.УстановитьЗначениеПараметра("ПараметрДокумент1", Документы.Документ1.ПустаяСсылка());
КонецЕсли;
КонецПроцедуры
Иногда требуется, чтобы пользователь не мог самостоятельно отключить или изменить установленный нами отбор через стандартную кнопку «Настроить список». В таких случаях вместо прямого изменения параметров запроса лучше использовать ФиксированныеНастройки компоновщика настроек динамического списка.
Рассмотрим, как это реализовать программно:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ДокументФильтр") И ЗначениеЗаполнено(Параметры.ДокументФильтр) Тогда
// Создаем новый элемент отбора в фиксированных настройках
ЭлементОтбора = Список.КомпоновщикНастроек.ФиксированныеНастройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
// Формируем массив ссылок из табличной части Документа1
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Документ1ТабличнаяЧасть.Документ2 КАК Документ2
|ИЗ
| Документ.Документ1.ТабличнаяЧасть КАК Документ1ТабличнаяЧасть
|ГДЕ
| Документ1ТабличнаяЧасть.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Параметры.ДокументФильтр);
ЭлементОтбора.ПравоеЗначение = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Документ2");
ЭлементОтбора.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Этот метод считается более надежным для жестких бизнес-ограничений, так как он полностью скрывает механику отбора от конечного пользователя.
Проанализируем важный нюанс: если пользователь не нажимает на кнопку выбора, а начинает вводить название или номер документа прямо в текстовое поле, форма выбора не открывается. В этом случае наши настройки в ПриСозданииНаСервере не сработают.
Для решения этой проблемы необходимо задействовать обработчик ОбработкаПолученияДанныхВыбора в модуле менеджера Документа2. В этот обработчик также можно передать параметры через свойство элемента формы ПараметрыВыбора. На форме обработки, где выбирается Документ2, в событии ПриИзменении для Документа1 следует динамически обновлять свойство ПараметрыВыбора:
&НаКлиенте
Процедура ОбъектДляФильтрацииПриИзменении(Элемент)
// Обновляем параметры выбора для поля Документ2, чтобы работал быстрый поиск
НовыйПараметр = Новый ПараметрВыбора("Отбор.ДокументФильтр", Объект.ОбъектДляФильтрации);
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(НовыйПараметр);
Элементы.ВыбираемыйДокумент.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
КонецПроцедуры
Подведем итог. Для качественной реализации фильтрации в форме выбора необходимо:
ОткрытьФорму с передачей параметров.ВЫБРАТЬ РАЗЛИЧНЫЕ для исключения дублей.ПриСозданииНаСервере формы выбора.Документ2 может перестать соответствовать условиям, и его, возможно, стоит очистить или проверить на корректность.Выяснив причину возникновения дублей и научившись передавать параметры между формами, мы получаем гибкий инструмент управления пользовательским интерфейсом, который делает работу с программой интуитивно понятной и защищает от ввода некорректных данных.