Как настроить отбор при вводе по строке в управляемом приложении 1С 8.3

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

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

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

Анализ типовых ошибок при ручном переопределении автоподбора

Рассмотрим код, с которого начинаются подобные проблемы:


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

При реализации серверной функции получения данных разработчики часто допускают ряд критических ошибок:

  1. Передача строки вместо ссылки. Если поле ввода связано с реквизитом ссылочного типа (например, СправочникСсылка.Сотрудники), то коллекция ДанныеВыбора типа СписокЗначений должна содержать в свойстве Значение именно ссылку на элемент справочника, а не его текстовое наименование. Если поместить туда строку, платформа не сможет сопоставить результат с типом поля и либо задействует стандартный механизм поиска, игнорируя отбор, либо очистит поле при завершении ввода.
  2. Влияние пользовательской истории выбора. Начиная с версии 8.3, в платформе действует механизм автоподмешивания ранее выбранных значений. Даже если запрос сформировал правильный список, платформа автоматически добавляет в выпадающее меню элементы из персональной истории выбора текущего пользователя.
  3. Ошибки в кадровых запросах. Использование виртуальной таблицы РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних без передачи даты среза приводит к получению данных на текущую дату, а не на дату документа. Кроме того, последнее событие может оказаться увольнением из указанной организации. Некорректное соединение с интервальным регистром без наложения фильтра по периодам также размножает строки.
  4. Производительность. Событие АвтоПодбор генерируется при наборе каждого символа. Выполнение тяжелых запросов к базе данных при каждом нажатии клавиши создает неоправданную нагрузку на сервер.

Способ 1. Использование механизма Связи параметров выбора (рекомендуемый)

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

Разберем настройку по шагам:

  1. Откроем форму документа в конфигураторе и выделим элемент формы — колонку СотрудникиСотрудник.
  2. В палитре свойств найдем пункт Связи параметров выбора и нажмем кнопку открытия диалога.
  3. Добавим новую связь: в качестве параметра выберем Отбор.ГоловнаяОрганизация (или Отбор.Организация), а в качестве реквизита укажем Объект.Организация.
  4. Чтобы платформа не подмешивала сотрудников из других организаций, ранее выбранных пользователем в других документах, найдем в свойствах элемента свойство История выбора при вводе и переключим его в значение Не использовать.

При такой настройке платформа автоматически применяет отбор и при интерактивном открытии формы выбора, и при вводе текста по строке.

Способ 2. Программная установка параметров выбора при изменении шапки

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

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


&НаСервере
Процедура УстановитьОтборСотрудниковПоОрганизации()
    
    Если Объект.Организация.Пустая() Тогда
        Элементы.СотрудникиСотрудник.ПараметрыВыбора = Новый ФиксированныйМассив(Новый Массив);
        Возврат;
    КонецЕсли;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    КадроваяИстория.Сотрудник КАК Сотрудник
        |ИЗ
        |    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&Период, Организация = &Организация) КАК КадроваяИстория
        |ГДЕ
        |    НЕ КадроваяИстория.Сотрудник.ПометкаУдаления
        |    И КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)";
    
    Запрос.УстановитьПараметр("Организация", Объект.Организация);
    Запрос.УстановитьПараметр("Период", Объект.Дата);
    
    МассивСотрудников = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Сотрудник");
    
    НовыйПараметр = Новый ПараметрВыбора("Отбор.Ссылка", Новый ФиксированныйМассив(МассивСотрудников));
    
    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(НовыйПараметр);
    
    Элементы.СотрудникиСотрудник.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
    
КонецПроцедуры

&НаКлиенте
Процедура ОрганизацияПриИзменении(Элемент)
    УстановитьОтборСотрудниковПоОрганизации();
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    УстановитьОтборСотрудниковПоОрганизации();
КонецПроцедуры

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

Способ 3. Переопределение в модуле менеджера справочника

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

Рассмотрим структуру реализации в модуле менеджера справочника Сотрудники:


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

Способ 4. Корректное использование события АвтоПодбор

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

Посмотрим на правильный рабочий код формы:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Отключаем подмешивание ранее выбираемых пользователей
    Элементы.СотрудникиСотрудник.ИсторияВыбораПриВводе = ИсторияВыбораПриВводе.НеИспользовать;
КонецПроцедуры

&НаКлиенте
Процедура СотрудникиСотрудникАвтоПодбор(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, Ожидание, СтандартнаяОбработка)
    
    Если НЕ Объект.Организация.Пустая() И СтрДлина(СокрЛП(Текст)) >= 2 Тогда
        СтандартнаяОбработка = Ложь;
        ДанныеВыбора = ПолучитьДанныеВыбораСотрудниковНаСервере(Текст, Объект.Организация, Объект.Дата);
    КонецЕсли;
    
КонецПроцедуры

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

Обратите внимание на вызов процедуры с директивой &НаСервереБезКонтекста: это снижает объем передаваемых данных между клиентом и сервером при быстром вводе текста, а проверка минимальной длины строки (от 2 символов) исключает выполнение запроса при случайных нажатиях клавиш.

← На главную