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