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