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