Как правильно устанавливать программные отборы в динамическом списке 1С без дублирования условий?

Программист 1С v8.3 (Управляемые формы) 1С:Комплексная автоматизация IT и автоматизация бизнеса
← На главную

Работа с динамическими списками в 1С:Предприятие 8.3 — это ежедневная задача разработчика. Часто возникает необходимость накладывать на список несколько фильтров одновременно (например, по заявителю и по статусу), при этом параметры фильтрации могут меняться пользователем динамически. Одной из самых частых проблем при реализации такого функционала является «засорение» коллекции Список.Отбор.Элементы. Если добавлять новые элементы отбора при каждом изменении фильтра, не проверяя существующие, система начнет накапливать условия, что приводит либо к некорректной фильтрации, либо к получению пустого результата.

Давайте разберем, как реализовать механизм гибкой фильтрации, который будет работать корректно и стабильно.

Почему стандартный метод добавления не подходит?

Когда мы используем метод Список.Отбор.Элементы.Добавить(), мы создаем новый объект ЭлементОтбораКомпоновкиДанных. Если пользователь меняет значение отбора по «Статусу» несколько раз, в коллекции появляются новые элементы с тем же полем «Статус». СКД воспринимает это как логическое «И» между всеми элементами: Статус = 1 И Статус = 2. Очевидно, что ни одна запись не может соответствовать такому условию, и список становится пустым.

Решение 1: Использование универсальной процедуры поиска и изменения отбора

Наиболее надежный способ — это проверка наличия отбора перед его созданием. Вместо того чтобы бездумно добавлять элементы, мы должны «найти и обновить» существующий или добавить новый, если фильтрация по этому полю еще не была задана.

Рассмотрим пример универсальной процедуры, которую можно использовать в модуле формы для управления любым отбором:


Процедура УстановитьЗначениеОтбора(лкОтборы, ИмяПоля, ВидОперации = Неопределено, ЗначениеПоля = Неопределено, ИспользоватьОтбор = Неопределено)
    лкНайдено = Ложь;
    лкПоле = Новый ПолеКомпоновкиДанных(ИмяПоля);
    ЕстьЗначение = ЗначениеЗаполнено(ЗначениеПоля);
    лкВидОперации = ?(ВидОперации = Неопределено, ВидСравненияКомпоновкиДанных.Равно, ВидОперации);
    
    Для каждого лкСтр Из лкОтборы Цикл
        Если ТипЗнч(лкСтр) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
            Если лкСтр.ЛевоеЗначение = лкПоле Тогда
                лкНайдено = Истина;
                лкСтр.ПравоеЗначение = ЗначениеПоля;
                Если ИспользоватьОтбор = Неопределено Тогда
                    лкСтр.Использование = ЕстьЗначение;
                Иначе
                    лкСтр.Использование = ИспользоватьОтбор;
                КонецЕсли;
                Прервать;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Если Не лкНайдено и ЕстьЗначение Тогда
        лкСтр = лкОтборы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        лкСтр.ЛевоеЗначение = лкПоле;
        лкСтр.ВидСравнения = лкВидОперации;
        лкСтр.ПравоеЗначение = ЗначениеПоля;
        лкСтр.Использование = Истина;
    КонецЕсли;
КонецПроцедуры

Как это работает:

  1. Мы перебираем все элементы коллекции Список.Отбор.Элементы.
  2. Ищем элемент, у которого ЛевоеЗначение совпадает с именем нашего поля.
  3. Если нашли — просто обновляем ПравоеЗначение и свойство Использование.
  4. Если не нашли — добавляем новый элемент в коллекцию.

Решение 2: Использование возможностей БСП

В типовых конфигурациях (например, КА 2.4, ERP) существуют встроенные механизмы, которые уже содержат необходимую логику. Использование метода ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка позволяет делегировать задачу по поиску и изменению элемента стандартным функциям платформы. Это избавляет вас от необходимости написания собственного кода.

Пример использования функции для установки статуса:


ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
    Список, 
    "Статус", 
    ОтборСтатус, 
    ВидСравненияКомпоновкиДанных.Равно, 
    , 
    ЗначениеЗаполнено(ОтборСтатус)
);

Параметр ЗначениеЗаполнено(ОтборСтатус) здесь критически важен: если статус не выбран, свойство Использование будет установлено в Ложь, что фактически отключает фильтр, не удаляя его из списка.

Важные рекомендации по реализации

  1. Не используйте Список.Отбор.Элементы.Очистить(), если у вас одновременно работают несколько независимых фильтров. Это удалит все настройки, включая те, которые были заданы пользователем вручную.
  2. Управляйте свойством Использование. Если фильтр нужно «сбросить», просто установите Использование = Ложь. Это позволяет сохранить структуру отбора и восстановить его в любой момент.
  3. Используйте ПолеКомпоновкиДанных. Всегда передавайте имя поля как объект этого типа, чтобы система корректно идентифицировала целевое поле в структуре отборов динамического списка.
  4. Синхронизация. Если вы выводите элементы отбора в пользовательскую часть интерфейса, убедитесь, что ваши программные действия отражают состояние настроек в КомпоновщикНастроек.ПользовательскиеНастройки, иначе пользователь может столкнуться с несоответствием того, что он видит на экране, и того, что реально отфильтровано.

Применяя эти подходы, вы сможете создать гибкую и эффективную систему фильтрации, которая будет работать быстро и не приведет к возникновению ошибок логики в ваших списках.

← На главную