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