Как программно настроить отбор в форме выбора по данным табличной части документа

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

В разработке на платформе 1С:Предприятие 8.3 часто возникает задача ограничить список выбора объектов на основании данных текущей строки. Если речь идет о реквизитах «шапки» документа или простых реквизитах строки, стандартный механизм СвязиПараметровВыбора (ChoiceParameterLinks) справляется отлично. Однако, когда нам необходимо отфильтровать список документов по наличию определенного значения в их табличных частях, мы сталкиваемся с архитектурным ограничением платформы.

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

Анализ проблемы: почему стандартные связи не видят табличные части

Механизм СвязиПараметровВыбора работает по принципу автоматической генерации условий для динамического списка формы выбора. Когда вы указываете связь, платформа пытается построить простой SQL-запрос с условием ГДЕ. Если реквизит находится в шапке, это прямое поле таблицы. Но табличная часть — это отдельная подчиненная таблица.

Попытка прописать путь к данным вида Отбор.ТабличнаяЧасть1.РеквизитНомер вызывает ошибку, так как система не может автоматически определить логику связи: должен ли документ подходить, если хотя бы одна строка ТЧ соответствует условию, или если все строки соответствуют. Поэтому для таких сценариев приходится использовать программные методы управления формой и динамическим списком.

Вариант 1. Программная установка простых связей (для реквизитов шапки)

Для начала рассмотрим, как программно устанавливаются связи параметров выбора для обычных полей. Это полезно, когда структура формы динамическая или связи зависят от условий. Разберем пример установки связи по дате:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Очищаем текущие связи, если они были установлены в конфигураторе
    Элементы.ТабличнаяЧасть1Ссылка.СвязиПараметровВыбора = Новый ФиксированныйМассив(Новый Массив);
    
    НовыйМассивСвязей = Новый Массив();
    
    // Создаем новую связь: Отбор.ДатаДок в выбираемом объекте будет равен ДатеДок1 из текущей строки
    НоваяСвязь = Новый СвязьПараметраВыбора("Отбор.ДатаДок", "Объект.ТабличнаяЧасть1.ТекущиеДанные.ДатаДок1");
    НовыйМассивСвязей.Добавить(НоваяСвязь);
    
    // Применяем массив к элементу формы
    Элементы.ТабличнаяЧасть1Ссылка.СвязиПараметровВыбора = Новый ФиксированныйМассив(НовыйМассивСвязей);
КонецПроцедуры

Этот код отлично работает для полей верхнего уровня, но, как мы выяснили, он бессилен перед табличными частями. Перейдем к решению основной задачи.

Вариант 2. Реализация отбора по табличной части через параметры формы

Чтобы реализовать сложный фильтр (по вложенным строкам), нам нужно выполнить два шага: передать значение из текущей строки в форму выбора и правильно обработать его при открытии этой формы. Рассмотрим этот процесс по шагам.

Шаг 1. Передача параметра в событии НачалоВыбора

В форме документа, где пользователь осуществляет выбор, мы должны перехватить стандартный процесс и добавить свой параметр в структуру ПараметрыВыбора.


&НаКлиенте
Процедура ТабличнаяЧасть1СсылкаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Отключаем стандартное открытие
    
    // Получаем текущие данные строки
    ТекущаяСтрока = Элементы.ТабличнаяЧасть1.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Формируем параметры для открытия формы выбора
    ПараметрыВыбора = Новый Структура;
    ПараметрыВыбора.Вставить("ОтборПоНомеруВТЧ", ТекущаяСтрока.Номер);
    // Можно добавить и другие параметры, например, множественный выбор или закрытие при выборе
    
    ОткрытьФорму("Документ.Документ1.ФормаВыбора", ПараметрыВыбора, Элемент);
    
КонецПроцедуры

Шаг 2. Обработка параметра в форме выбора

Теперь проанализируем, как принять этот параметр в форме выбора Документа1. Нам нужно модифицировать КомпоновщикНастроек динамического списка Список.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем наличие нашего специального параметра
    Если Параметры.Свойство("ОтборПоНомеруВТЧ") Тогда
        
        // Создаем новый элемент отбора компоновки данных
        ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        
        // Указываем поле, по которому будем фильтровать. 
        // Важно: Поле должно быть доступно в запросе динамического списка.
        // Если это реквизит ТЧ, путь будет выглядеть так:
        ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТабличнаяЧасть1.Номер");
        
        ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
        ЭлементОтбора.ПравоеЗначение = Параметры.ОтборПоНомеруВТЧ;
        ЭлементОтбора.Использование = Истина;
        
    КонецЕсли;
    
КонецПроцедуры

Важное примечание: Чтобы отбор по полю ТабличнаяЧасть1.Номер заработал, в самом динамическом списке формы выбора в тексте запроса должно быть разрешено использование табличных частей (неявное соединение). Если платформа выдает ошибку о недопустимости использования коллекции в отборе, необходимо изменить текст запроса динамического списка.

Вариант 3. Использование произвольного запроса в динамическом списке

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

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


ВЫБРАТЬ
    Документ1.Ссылка,
    Документ1.Дата,
    Документ1.Номер
ИЗ
    Документ.Документ1 КАК Документ1
ГДЕ
    (&НеФильтроватьПоТЧ ИЛИ Документ1.Ссылка В (
        ВЫБРАТЬ РАЗЛИЧНЫЕ
            ТЧ.Ссылка
        ИЗ
            Документ.Документ1.ТабличнаяЧасть1 КАК ТЧ
        ГДЕ
            ТЧ.Номер = &НужныйНомер
    ))

Теперь в процедуре ПриСозданииНаСервере нам достаточно просто установить значения параметров запроса:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Если Параметры.Свойство("ОтборПоНомеруВТЧ") Тогда
        Список.Параметры.УстановитьЗначениеПараметра("НеФильтроватьПоТЧ", Ложь);
        Список.Параметры.УстановитьЗначениеПараметра("НужныйНомер", Параметры.ОтборПоНомеруВТЧ);
    Иначе
        Список.Параметры.УстановитьЗначениеПараметра("НеФильтроватьПоТЧ", Истина);
        Список.Параметры.УстановитьЗначениеПараметра("НужныйНомер", "");
    КонецЕсли;
    
КонецПроцедуры

Этот метод считается наиболее «чистым» и производительным с точки зрения работы СУБД, так как мы явно используем вложенный запрос с оператором ВЫБРАТЬ РАЗЛИЧНЫЕ, что исключает дублирование ссылок в списке при совпадении условий в нескольких строках табличной части.

Дополнительные рекомендации

Разберем еще несколько нюансов, которые помогут сделать работу механизма выбора безупречной:

  1. Обработка получения данных выбора: Если вам нужно, чтобы фильтр работал не только при открытии формы, но и при быстром вводе по строке, реализуйте аналогичную логику в модуле менеджера Документа1 в обработчике ОбработкаПолученияДанныхВыбора. Параметры, переданные в ПараметрыВыбора, попадут и туда.
  2. Интерактивное изменение: Помните, что если пользователь изменит значение в строке-источнике (например, поменяет дату или номер), а форма выбора уже открыта, она не обновится сама. Для синхронизации нужно либо закрывать форму, либо принудительно обновлять её через ОповеститьОбИзменении.
  3. Визуализация: Хорошим тоном считается информирование пользователя о том, что список отфильтрован. Можно программно добавить декорацию-надпись в шапку формы выбора, если активен специальный параметр отбора.

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

← На главную