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