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