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