При разработке мобильных и настольных приложений на платформе 1С часто возникает задача: сформировать сложную выборку данных с помощью тяжелого запроса (объединения нескольких регистров, временные таблицы, сложные группировки), вывести результат в таблицу на форме и предоставить пользователю возможность удобного «живого» поиска по мере ввода текста.
Штатный механизм полнотекстового живого поиска встроен в элемент ДинамическийСписок, однако динамический список накладывает жесткие ограничения на текст запроса и не поддерживает произвольные таблицы значений в качестве прямого источника данных. Разберем основные архитектурные подходы к реализации живого поиска по сложным наборам данных на мобильной платформе.
Проанализируем популярное заблуждение: попытку скрыть неподходящие строки через свойство Видимость в условном оформлении формы. В управляемых формах и мобильной платформе условное оформление не умеет физически исключать строки из отображения. Свойство Видимость применяется к элементам формы в целом, а свойство Отображать управляет только флажками и переключателями. Попытка замаскировать несовпадающие строки через оформление оставляет пустые полосы в таблице, что делает интерфейс непригодным для работы на мобильном устройстве.
Рассмотрим подход, при котором результат сложного запроса временно записывается во вспомогательный регистр сведений, а на форме отображается ДинамическийСписок с источником данных из этого регистра. Это позволяет использовать стандартную строку поиска платформы 1С без написания собственного движка фильтрации.
Для реализации создадим универсальный регистр сведений ДанныеДляДинамическихСписков со следующей структурой:
ИмяДанных (Строка), Измерение1, Измерение2 (произвольный тип или ссылки).Ресурс1, Ресурс2, Ресурс3, Ресурс4, Ресурс5.Посмотрим на пример процедуры серверной записи данных из таблицы значений в служебный регистр:
&НаСервере
Процедура ЗаписатьДанныеДляДинамическогоСписка(ИмяДанных, Таб, Измерения, Ресурсы)
Измерения = СтрЗаменить(Измерения, ",", Символы.ПС);
Ресурсы = СтрЗаменить(Ресурсы, ",", Символы.ПС);
Набор = РегистрыСведений.ДанныеДляДинамическихСписков.СоздатьНаборЗаписей();
Набор.Отбор.ИмяДанных.Установить(ИмяДанных);
Для Каждого Стр Из Таб Цикл
НоваяЗапись = Набор.Добавить();
НоваяЗапись.ИмяДанных = ИмяДанных;
Для П = 1 По СтрЧислоСтрок(Измерения) Цикл
ИмяКолонки = СтрПолучитьСтроку(Измерения, П);
НоваяЗапись["Измерение" + П] = Стр[ИмяКолонки];
КонецЦикла;
Для П = 1 По СтрЧислоСтрок(Ресурсы) Цикл
ИмяКолонки = СтрПолучитьСтроку(Ресурсы, П);
НоваяЗапись["Ресурс" + П] = Стр[ИмяКолонки];
КонецЦикла;
КонецЦикла;
Набор.Записать();
КонецПроцедуры
Разберем вызов этой процедуры при подготовке данных формы:
ЗаписатьДанныеДляДинамическогоСписка("СписокЗаказов", ТабЗн, "Контрагент,ДоговорКонтрагента", "ТипЗаказа,Количество,Вес,Закрыт");
После записи на форме настраивается ДинамическийСписок с произвольным запросом к регистру сведений с отбором по полю ИмяДанных = &ИмяДанных. Пользователь получает полноценное поле поиска с серверной фильтрацией и стандартным поведением динамического списка.
Если создание промежуточных записей в базе данных нежелательно из-за объема или накладных расходов на мобильном накопителе, организуем поиск целиком в оперативной памяти формы.
Разберем архитектуру решения по шагам:
СтрокаПоиска и привязываем его к элементу ввода на форме.ТаблицаОтображения типа ДанныеФормыКоллекция.АвтоПодборТекста.Посмотрим на пример клиентского кода обработки ввода текста:
&НаКлиенте
Процедура СтрокаПоискаАвтоПодборТекста(Элемент, Текст, ДанныеВыбора, ПараметрыИзвлечения, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ЭтаФорма.СтрокаПоиска = Текст;
// Перезапускаем обработчик ожидания при каждом нажатии клавиши
ОтключитьОбработчикОжидания("ВыполнитьЖивойПоиск");
ПодключитьОбработчикОжидания("ВыполнитьЖивойПоиск", 0.4, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьЖивойПоиск()
ОтфильтроватьТаблицуНаСервере(ЭтаФорма.СтрокаПоиска);
КонецПроцедуры
На сервере для быстрого отбора по подстроке воспользуемся объектом ПостроительЗапроса, который умеет выполнять фильтрацию прямо по объекту ТаблицаЗначений без обращений к таблицам базы данных:
&НаСервере
Процедура ОтфильтроватьТаблицуНаСервере(Знач ТекстПоиска)
ПолнаяТаблица = ПолучитьИзВременногоХранилища(АдресПолнойТаблицы);
Если ПустаяСтрока(ТекстПоиска) Тогда
ЗначениеВРеквизитФормы(ПолнаяТаблица, "ТаблицаОтображения");
Возврат;
КонецЕсли;
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ПолнаяТаблица);
// Добавляем условие поиска по нужной колонке
Отбор = Построитель.Отбор.Добавить("Наименование");
Отбор.ВидСравнения = ВидСравнения.Содержит;
Отбор.Значение = СокрЛП(ТекстПоиска);
Отбор.Использование = Истина;
Результат = Построитель.Выполнить().Выгрузить();
ЗначениеВРеквизитФормы(Результат, "ТаблицаОтображения");
КонецПроцедуры
Проанализируем еще один высокопроизводительный вариант для мобильной платформы — вывод сформированной таблицы в элемент ПолеHTMLДокумента. В этом сценарии таблица преобразуется в HTML-разметку или передается в виде массива JSON на клиентскую сторону. Фильтрация строк по вводу в строку поиска выполняется на чистом JavaScript внутри веб-компонента.
Главное преимущество этого способа — полное отсутствие вызовов сервера и контекстных трансформаций данных формы при вводе каждого символа, что дает максимальную плавность интерфейса даже на бюджетных мобильных устройствах.