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

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

При разработке интерфейсов в среде 1С:Предприятие 8.3 (Управляемые формы) программисты часто сталкиваются с классической архитектурной дилеммой. Нам необходимо сделать так, чтобы одна и та же форма выбора (например, справочника Работники) в одном сценарии открывалась с жесткой фильтрацией по параметру (например, по должности сотрудника при выборе из документа), а в другом сценарии — без каких-либо ограничений (например, при открытии справочника напрямую из панели разделов).

Разберем суть проблемы. Если мы пропишем условие связи или отбора непосредственно в тексте запроса динамического списка в конфигураторе:


ГДЕ
    СостояниеРаботниковСрезПоследних.Должность В (&Должность)

то при любой попытке открыть форму без предварительной установки параметра &Должность платформа выдаст критическую ошибку: «Параметр не установлен (&Должность)». Стандартный механизм отборов динамического списка (свойство Отбор) по техническому заданию часто использовать нельзя или нецелесообразно из-за особенностей связи таблиц в сложном запросе.

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

---

Способ 1. Использование фигурных скобок (Механизм СКД) — наиболее правильный подход

Самым элегантным и стандартным методом решения этой проблемы в платформе 1С является использование расширения языка запросов для системы компоновки данных (СКД). С помощью фигурных скобок {} мы можем указать платформе, что данное условие в запросе является необязательным. Если параметр передан — условие применится. Если не передан — платформа просто исключит эту строку из результирующего SQL-запроса к СУБД.

Рассмотрим по шагам реализацию этого метода:

  1. Откроем конструктор схемы запроса нашего динамического списка (свойство Настройка списка -> Текст запроса).
  2. Заключим наше условие отбора в фигурные скобки следующим образом:

ВЫБРАТЬ
    Работники.Ссылка КАК Ссылка,
    Работники.Код КАК Код,
    Работники.Наименование КАК Наименование
ИЗ
    Справочник.Работники КАК Работники
    {ГДЕ (СостояниеРаботниковСрезПоследних.Должность В (&Должность))}

Теперь напишем код для вызова формы выбора из нашего документа. Передавать параметр мы будем напрямую через структуру параметров открываемой формы:


&НаКлиенте
Процедура ДиспетчерНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Получаем ссылку на должность, по которой нужно установить фильтр
    ДолжностьСсылкой = ПолучитьДолжностьДляФильтра(Элемент.Имя); 
    
    // Формируем параметры открытия формы
    ПараметрыВыбора = Новый Структура;
    ПараметрыВыбора.Вставить("Должность", ДолжностьСсылкой);
    
    // Открываем форму выбора
    ОткрытьФорму("Справочник.Работники.ФормаВыбора", ПараметрыВыбора, Элемент);
    
КонецПроцедуры

Далее нам необходимо обработать этот параметр в самой открываемой форме выбора. Перейдем в модуль формы выбора справочника Работники и пропишем код в обработчике события ПриСозданииНаСервере:


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

Преимущества метода: Запрос автоматически оптимизируется платформой. Если параметр не передан, СУБД не выполняет лишних соединений и проверок, что положительно сказывается на производительности системы.

---

Способ 2. Использование управляющего флага-переключателя в запросе

Если по какой-то причине использование фигурных скобок нежелательно (например, при сложной иерархии вложенных запросов, где СКД может вести себя непредсказуемо), мы можем применить обходной маневр через логическое условие ИЛИ.

Для этого введем в запрос дополнительный булев параметр &ОтбиратьПоДолжности, который будет регулировать, нужно ли применять отбор в данный момент.

Проанализируем структуру такого запроса:


ГДЕ
    (НЕ &ОтбиратьПоДолжности) 
    ИЛИ СостояниеРаботниковСрезПоследних.Должность В (&Должность)

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


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

Преимущества метода: Абсолютная стабильность работы в любых версиях платформы 1С. Логика работы запроса полностью прозрачна и легко поддается отладке в консоли запросов.

---

Способ 3. Динамическая модификация текста запроса на сервере

Этот способ можно назвать "хирургическим". Мы не используем ухищрения в самом запросе, а физически удаляем или добавляем строку с условием ГДЕ в зависимости от того, передал ли пользователь параметр при открытии формы.

Изначально в конфигураторе в динамическом списке пишем запрос со стандартным жестким условием:


// ... Текст запроса в конфигураторе ...
ИЗ
    Справочник.Работники КАК Работники
ГДЕ
    СостояниеРаботниковСрезПоследних.Должность В (&Должность)

В модуле формы выбора справочника перехватываем управление при создании формы на сервере. Если параметр не пришел, мы просто "вырезаем" условие отбора из текста запроса:


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

Важное предупреждение: Данный метод требует предельной осторожности. Если в будущем другой разработчик изменит форматирование запроса в конфигураторе (например, добавит лишний пробел, перенос строки или переведет ключевые слова в другой регистр), функция СтрЗаменить перестанет находить целевую строку. Это приведет к внезапному падению формы с ошибкой неинициализированного параметра.

---

Резюме: какой метод выбрать?

Мы детально рассмотрели три практических способа решения проблемы. Подведем итоги совместного анализа:

← На главную