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