Как правильно добавить условие и настроить отбор в динамическом списке 1С

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

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

В этой статье мы подробно разберем, как правильно работать с условиями в динамических списках, почему стандартный подход с параметрами в запросе может приводить к ошибкам, и как элегантно решить задачу с помощью программной настройки компоновки данных и механизмов БСП (Библиотеки стандартных подсистем).


Выясняем причину: почему возникает ошибка «Не задано значение параметра»?

Рассмотрим ситуацию, с которой столкнулся автор темы. В запросе динамического списка было прописано условие в фигурных скобках:


{ГДЕ СправочникДоговорыКонтрагентов.Контрагент = &Контрагент}
{ГДЕ СправочникДоговорыКонтрагентов.Организация = &Организация}
{ГДЕ СправочникДоговорыКонтрагентов.ДатаОкончанияДействия >= &Дата}

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

Фигурные скобки {} в запросе динамического списка указывают на то, что данное поле доступно для построения условий Системой компоновки данных (СКД). Однако синтаксис {ГДЕ Поле = &Параметр} имеет важную особенность: условие действительно становится необязательным и не накладывается, если нет явного требования. Но сам параметр &Параметр платформа продолжает считать объявленным в запросе. Если вы не передадите его значение в коллекцию параметров динамического списка или явно не отключите его использование, система выдаст ошибку.

Для создания действительно необязательных полей отбора правильнее использовать синтаксис без объявления параметров в правой части:


{ГДЕ СправочникДоговорыКонтрагентов.Контрагент, СправочникДоговорыКонтрагентов.Организация}

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


Способ 1. Программное наложение сложного отбора с группой «ИЛИ» (Рекомендуемый)

Давайте разберем, как решить задачу автора темы: отобразить договоры, у которых дата окончания либо больше или равна рабочей дате, либо не заполнена вовсе. Самый надежный и современный способ — вообще не трогать текст запроса динамического списка, а сформировать отбор программно в виде группы условий.

Этот способ хорош тем, что он никак не влияет на структуру запроса, не требует объявления параметров и полностью исключает возникновение ошибок при открытии формы из «нетипичных» мест. Проанализируем пример кода, который необходимо разместить в обработчике ПриСозданииНаСервере формы выбора:


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

Преимущества данного подхода:

  1. Запрос динамического списка остается «чистым», что облегчает его чтение и поддержку.
  2. Если форма открывается без параметра Дата (например, из акта сверки), этот блок кода просто пропускается, и список открывается без ошибок, выводя полный перечень договоров.
  3. Условие НеЗаполнено одинаково хорошо отрабатывает пустые значения для типов данных «Дата» в любых СУБД (будь то Microsoft SQL Server, PostgreSQL или файловый вариант базы данных).

Способ 2. Управление активностью параметров через функции БСП

Если специфика вашей задачи всё же требует использования параметров внутри текста запроса динамического списка, мы должны гарантировать системе, что неиспользуемые параметры будут деактивированы. В типовых конфигурациях (таких как УТ 11, КА 2, ERP) для этого предусмотрен удобный инструментарий Библиотеки стандартных подсистем (БСП).

Рассмотрим, как правильно управлять параметрами запроса динамического списка с помощью общего модуля ОбщегоНазначенияКлиентСервер. Метод УстановитьПараметрДинамическогоСписка принимает четыре параметра, где последний отвечает за активность (использование) этого параметра:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Управляем параметром "Организация"
    ЕстьОрганизация = ЗначениеЗаполнено(Параметры.Организация);
    ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(
        Список, 
        "Организация", 
        Параметры.Организация, 
        ЕстьОрганизация
    );
    
    // Управляем параметром "Контрагент"
    ЕстьКонтрагент = ЗначениеЗаполнено(Параметры.Контрагент);
    ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(
        Список, 
        "Контрагент", 
        Параметры.Контрагент, 
        ЕстьКонтрагент
    );
    
    // Управляем параметром "Статус"
    ЕстьСтатус = ЗначениеЗаполнено(Параметры.Статус);
    ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(
        Список, 
        "Статус", 
        Параметры.Статус, 
        ЕстьСтатус
    );

КонецПроцедуры

Когда мы передаем в четвертый параметр значение Ложь (в случае, если реквизит не заполнен), платформа полностью исключает это условие из итогового SQL-запроса к базе данных. Ошибка инициализации параметров при этом не возникает.


Архитектурный нюанс: Фиксированные настройки против обычного отбора

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

  1. Обычный отбор (Список.Отбор):

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

  2. Фиксированные настройки (Список.ФиксированныеНастройки.Отбор):

    Эти условия накладываются жестко на уровне платформы. Пользователь не видит их в стандартном интерфейсе настройки списка и не может их обойти или отключить. Это идеальный инструмент для реализации строгой бизнес-логики (например, когда при выборе договора в документе по конкретной организации категорически запрещено показывать договоры других юридических лиц).

Для программной установки элементов в фиксированные настройки в БСП также есть готовая функция. Давайте посмотрим на пример ее вызова:


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

Используя этот метод, мы лаконично устанавливаем жесткий отбор по организации. Обратите внимание на последний параметр РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный — он делает отбор скрытым для пользователя, гарантируя целостность данных системы.


Чего делать точно не стоит: событие ПриПолученииДанных

В ходе обсуждения на форуме прозвучало предложение фильтровать данные в событии списка ПриПолученииДанных. Настоятельно рекомендуем избегать этого подхода для целей фильтрации!

Событие ПриПолученииДанных вызывается на клиенте при каждом выводе строк на экран. Попытка фильтровать или удалять строки на этом этапе приведет к колоссальному падению производительности («тормозам» интерфейса), нарушению постраничной навигации динамического списка и невозможности корректного поиска или отбора стандартными средствами платформы. Все отборы должны выполняться исключительно на уровне СУБД с помощью механизмов СКД динамического списка.

Резюме и лучшие практики

Для эффективной работы с динамическими списками придерживайтесь простых правил:

← На главную