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