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

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

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

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

Почему не нужно выполнять обработку пометок на сервере

Проанализируем распространенную ошибку: попытку отправить текущую строку на сервер и преобразовать данные формы через РеквизитФормыВЗначение. Такой подход создает сразу несколько проблем:

  1. Потеря идентификаторов строк. При конвертации ДанныеФормыДерево в объект ДеревоЗначений числовые идентификаторы строк формы теряются. Найти исходную строку по идентификатору после такого преобразования невозможно.
  2. Сброс состояния интерфейса. Последующий вызов ЗначениеВРеквизитФормы полностью пересоздает строки дерева на клиенте, генерируя новые идентификаторы, что сбрасывает текущую позицию курсора и раскрытые ветки.
  3. Задержки интерфейса. Каждый клик по флажку инициирует серверный вызов. При быстром переключении элементов интерфейс начинает зависать.

Коллекция ДанныеФормыДерево и её элементы типа ДанныеФормыЭлементДерева доступны для чтения и модификации непосредственно на клиенте. Вся логика пересчета пометок должна работать в процедуре &НаКлиенте.

Принцип работы алгоритма: две рекурсии

Корректная синхронизация флажков состоит из двух независимых направлений обхода:

  1. Спуск вниз по иерархии (к потомкам): при изменении флага у текущей строки мы рекурсивно передаем установленное значение всем вложенным элементам.
  2. Подъем вверх по иерархии (к родителям): после изменения дочернего элемента необходимо проверить состояние всех строк на текущем уровне и, если все подчиненные узлы отмечены (или сняты), скорректировать пометку у родительского узла, поднявшись рекурсивно до самого корня.

Пошаговая реализация на клиенте

Посмотрим на пример реализации. Предположим, что в дереве на форме есть колонка пометки с именем Пометка (тип Булево или Число).

Сначала создадим процедуру для каскадного спуска пометки к дочерним строкам:


&НаКлиенте
Процедура УстановитьПометкиПодчиненным(ЭлементДерева, ЗначениеПометки)
    Для Каждого Подчиненный Из ЭлементДерева.ПолучитьЭлементы() Цикл
        Подчиненный.Пометка = ЗначениеПометки;
        // Рекурсивный спуск на следующий уровень
        УстановитьПометкиПодчиненным(Подчиненный, ЗначениеПометки);
    КонецЦикла;
КонецПроцедуры

Далее реализуем функцию подъема по иерархии, которая проверяет состояние соседних строк и обновляет родительский узел:


&НаКлиенте
Процедура ОбновитьПометкуРодителей(ЭлементДерева)
    Родитель = ЭлементДерева.ПолучитьРодителя();
    Если Родитель = Неопределено Тогда
        // Достигли корня дерева
        Возврат;
    КонецЕсли;

    ВсеОтмечены = Истина;
    Для Каждого Сосед Из Родитель.ПолучитьЭлементы() Цикл
        Если Не Сосед.Пометка Тогда
            ВсеОтмечены = Ложь;
            Прервать;
        КонецЕсли;
    КонецЦикла;

    Родитель.Пометка = ВсеОтмечены;

    // Рекурсивный подъем на уровень выше
    ОбновитьПометкуРодителей(Родитель);
КонецПроцедуры

Подключение обработчика события

Назначим обработку в событие ПриИзменении поля флажка в таблице дерева (а не в события всей таблицы):


&НаКлиенте
Процедура ДеревоПометкаПриИзменении(Элемент)
    ТекущаяСтрока = Элементы.Дерево.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // 1. Спускаем пометку вниз всем дочерним узлам
    УстановитьПометкиПодчиненным(ТекущаяСтрока, ТекущаяСтрока.Пометка);

    // 2. Пересчитываем пометку вверх для родительских узлов
    ОбновитьПометкуРодителей(ТекущаяСтрока);
КонецПроцедуры

Поддержка трехпозиционного флажка

Если требуется отображать частичный выбор группы (когда в группе отмечена только часть элементов), выполним следующие настройки:

  1. Тип реквизита Пометка в дереве задаем как Число (длина 1): 0 — не отмечено, 1 — отмечено полностью, 2 — отмечено частично.
  2. У элемента формы (поля флажка) включаем свойство Трехпозиционный.
  3. В алгоритме подъема вверх вычисляем статус родителя: если у всех подчиненных 1 — родителю присваиваем 1; если у всех 0 — присваиваем 0; во всех остальных случаях (есть и 0, и 1, либо у кого-то 2) — родителю присваиваем 2.

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

← На главную