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