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

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

При разработке интерфейсов на управляемых формах часто возникает задача связать две таблицы. Например, когда пользователь выбирает строку в иерархическом дереве заявок, во второй таблице (корзине товаров) должны отобразиться только те строки, которые соответствуют выбранному узлу. Рассмотрим подробнее, как реализовать такой механизм без ошибок и проанализируем частые «глюки», с которыми сталкиваются программисты.

Разберем проблему на примере

Представим ситуацию: на форме есть дерево значений ДеревоЗаявок и таблица КорзинаВыдаваемыхТМЦ. Мы хотим обновлять отбор во второй таблице в событии ПриАктивизацииСтроки первого дерева. Зачастую разработчики пытаются конструировать объект ФиксированнаяСтруктура «на лету», передавая в конструктор строку с именами свойств и сами значения.

Посмотрим на ошибочный вариант реализации, который может приводить к неожиданным результатам при отладке:


&НаКлиенте
Процедура ДеревоЗаявокПриАктивизацииСтроки(Элемент)  
    ТекущиеДанные = Элементы.ДеревоЗаявок.ТекущиеДанные;  
    
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Если ТекущиеДанные.НомерЗаявки <> "" Тогда   
        ОтборПоКорзинe = Новый ФиксированнаяСтруктура("НомерЗаявки", ТекущиеДанные.НомерЗаявки);
        
        Если НЕ ТекущиеДанные.ТМЦ.Пустая() Тогда   
            ОтборПоКорзинe = Новый ФиксированнаяСтруктура("НомерЗаявки,ТМЦ", ТекущиеДанные.НомерЗаявки, ТекущиеДанные.ТМЦ);
            
            Если НЕ ТекущиеДанные.ФизЛицо.Пустая() Тогда   
                ОтборПоКорзинe = Новый ФиксированнаяСтруктура("НомерЗаявки,ТМЦ,ФизЛицо", ТекущиеДанные.НомерЗаявки, ТекущиеДанные.ТМЦ, ТекущиеДанные.ФизЛицо);
            КонецЕсли;    
        КонецЕсли;    
    КонецЕсли;    
    
    Элементы.КорзинаВыдаваемыхТМЦ.ОтборСтрок = ОтборПоКорзинe;
КонецПроцедуры

В этом коде кроется серьезный недостаток: логика формирования отбора жестко завязана на вложенность условий. Если, например, НомерЗаявки окажется пустой строкой, то структура отбора вообще не сформируется, даже если ФизЛицо или ТМЦ заполнены. Из-за этого может казаться, что платформа отрабатывает условие с ошибкой.

Правильный подход к формированию структуры отбора

Чтобы избежать подобных логических ловушек, выясним причину и применим более гибкий подход. Свойство ОтборСтрок таблицы формы принимает готовый объект ФиксированнаяСтруктура. Лучше всего сначала создать обычный объект Структура, наполнить его нужными параметрами в независимых условиях, а в самом конце передать эту структуру в конструктор фиксированной структуры.

Разберем по шагам рабочий и надежный вариант кода:


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

    СтруктураПараметров = Новый Структура;
    
    Если ЗначениеЗаполнено(ТекущиеДанные.НомерЗаявки) Тогда   
        СтруктураПараметров.Вставить("НомерЗаявки", ТекущиеДанные.НомерЗаявки);
    КонецЕсли;
    
    Если ЗначениеЗаполнено(ТекущиеДанные.ТМЦ) Тогда   
        СтруктураПараметров.Вставить("ТМЦ", ТекущиеДанные.ТМЦ);
    КонецЕсли;
    
    Если ЗначениеЗаполнено(ТекущиеДанные.ФизЛицо) Тогда   
        СтруктураПараметров.Вставить("ФизЛицо", ТекущиеДанные.ФизЛицо);
    КонецЕсли;
    
    Если СтруктураПараметров.Количество() > 0 Тогда
        Элементы.КорзинаВыдаваемыхТМЦ.ОтборСтрок = Новый ФиксированнаяСтруктура(СтруктураПараметров);
    Иначе
        Элементы.КорзинаВыдаваемыхТМЦ.ОтборСтрок = Неопределено;
    КонецЕсли;
КонецПроцедуры

Важные нюансы работы с деревьями и отборами

Проанализируем дополнительные особенности, которые нужно учитывать при работе со свойством ОтборСтрок и объектом ДанныеФормыДерево:

  1. Проверка на заполненность: Обратите внимание, что в исправленном коде мы используем метод ЗначениеЗаполнено() вместо Пустая(). Если в дереве используются разные уровни группировок, на одном из уровней колонка ссылочного типа может содержать Неопределено или Null. Вызов Пустая() у таких типов приведет к ошибке выполнения скрипта на клиенте. Метод ЗначениеЗаполнено() безопасен для любых типов данных.
  2. Данные иерархии: В иерархических деревьях, сформированных запросом с итогами, детальные записи могут не содержать дублирующую информацию родительских строк. Если вам нужно получить значение из вышестоящего уровня группировки, необходимо использовать метод ПолучитьРодителя() у объекта ДанныеФормыЭлементДерева в цикле до достижения корня.
  3. Ограничения отбора строк: Клиентское свойство ОтборСтрок поддерживает только точное совпадение по условию «И». Если вы передадите в структуру несколько ключей, платформа будет искать строки, где совпадают все указанные значения. Использование сложных условий (например, «ИЛИ» или сравнений «Больше/Меньше») в данном случае невозможно.
  4. Сброс фильтрации: Чтобы полностью очистить отбор и показать все строки таблицы, необходимо присвоить свойству значение Неопределено. Если вы передадите структуру с пустыми значениями, платформа попытается найти строки, где реквизиты буквально равны пустым ссылкам или пустым строкам.

Вопросы производительности и альтернативы

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

Рассмотрим, как можно оптимизировать этот процесс:

  1. Использование обработчика ожидания: Чтобы отбор не применялся каждую миллисекунду, пока пользователь быстро листает список стрелками вниз, вынесите применение отбора в отдельную процедуру. Вызывайте ее через ПодключитьОбработчикОжидания() с задержкой, например, 0.1 или 0.2 секунды.
  2. Ключ связи: Вместо отбора по трем разным колонкам (договор, ТМЦ, физлицо) формируйте один уникальный идентификатор строки (составной ключ или GUID) и устанавливайте отбор только по этой одной колонке. Это ускорит фильтрацию.
  3. Динамические списки: Если данные хранятся в информационной базе, а не являются временной таблицей значений на клиенте, целесообразно заменить таблицу на Динамический список. В этом случае вы можете передавать текущие значения в параметры запроса списка или в его программные отборы компоновки данных. Это позволит переложить нагрузку по фильтрации на сервер БД и использовать любые сложные логические конструкции.

Используя правильный подход к формированию структуры через метод Вставить(), вы сделаете ваш код надежным, легко читаемым и защищенным от логических ошибок при неполном заполнении данных в дереве.

← На главную