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