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