При переходе с обычных форм (ОФ) на управляемые формы (УФ) в системе 1С:Предприятие 8.3 пользователи часто сталкиваются с изменениями в поведении стандартных механизмов. Один из таких механизмов – это поиск по первым символам в табличном поле динамического списка. В обычных формах при наборе текста с клавиатуры курсор автоматически переходил к первой строке списка, наименование которой начиналось с введенных символов. В управляемых формах стандартное поведение отличается, что вызывает вопросы и потребность в адаптации. Давайте разберем эту ситуацию подробнее и рассмотрим возможные пути решения.
В управляемых формах, когда вы начинаете набирать текст, находясь в табличном поле динамического списка, система активирует быстрый поиск. Этот поиск имеет следующие характеристики:
Этот механизм, хотя и является мощным инструментом для общего поиска, не соответствует требованию быстрого позиционирования по первым символам в одной конкретной колонке без дополнительных действий пользователя, как это было в обычных формах.
Платформа 1С:Предприятие предоставляет несколько стандартных сочетаний клавиш для работы с поиском в списках:
Ctrl+F (Поиск): Активирует строку быстрого поиска (ту же, что появляется при начале набора текста), позволяя ввести или изменить поисковый запрос.Alt+F (Расширенный поиск): Открывает отдельное диалоговое окно для расширенного поиска, где можно задать более сложные условия поиска по разным колонкам, с различными видами сравнения (равно, содержит, начинается с и т.д.).Хотя эти инструменты полезны, они требуют явных действий от пользователя (нажать сочетание клавиш, ввести текст в отдельное поле или диалог), что не соответствует желаемому поведению "поиск на лету" при непосредственном наборе в списке.
Разница в поведении обусловлена архитектурными особенностями управляемых форм. В обычных формах значительная часть логики взаимодействия с данными и элементами управления выполнялась на стороне клиента. Это позволяло реализовать быстрый интерактивный поиск и позиционирование без постоянного обращения к серверу.
В управляемых формах взаимодействие клиента и сервера более строго регламентировано. Динамические списки представляют собой механизм, который эффективно загружает данные "по мере необходимости", обычно порциями, и выполняет запросы на сервере. Мгновенное позиционирование по одной колонке при каждом нажатии клавиши потребовало бы постоянной отправки частичных данных на сервер для перестроения списка или отбора, что могло бы существенно замедлить работу в клиент-серверном варианте, особенно на больших списках.
Таким образом, прямого аналога "быстрого" поиска по первым символам в одной колонке динамического списка, как это было в ОФ, в платформе 1С:Предприятие 8.3 не предусмотрено. Однако, мы можем эмулировать подобный функционал с помощью программных доработок.
Для того чтобы приблизить поведение динамического списка к функционалу обычных форм, когда при наборе текста происходит автоматическое позиционирование по первым символам в одной конкретной колонке, нам потребуется дополнительная программная доработка. Рассмотрим несколько подходов.
Этот метод является одним из наиболее распространенных и относительно простых для реализации. Он подразумевает создание на форме отдельного текстового поля ввода, при изменении значения в котором будет программно устанавливаться отбор на динамический список.
Создаем элемент формы: На форме, где расположен динамический список, добавляем новый элемент типа "Поле ввода". Назовем его, например, ПолеПоискаПоНаименованию. Убедимся, что его свойство ВидПоля установлено в "Поле ввода".
Создаем реквизит формы: Для этого поля ввода нам потребуется реквизит формы. Добавим реквизит формы с типом Строка, например, ТекстПоиска. Привязываем наше поле ввода к этому реквизиту через свойство Данные.
Обработчик события ПриИзменении: Для поля ПолеПоискаПоНаименованию создадим обработчик события ПриИзменении. Этот обработчик будет вызываться каждый раз, когда пользователь вводит или изменяет текст в этом поле.
Внутри обработчика мы будем устанавливать отбор для нашего динамического списка. Важно использовать отложенное выполнение (например, через таймер или обработчик ожидания), чтобы не перегружать систему частыми обращениями к серверу при каждом нажатии клавиши. Мы будем устанавливать отбор только после небольшой паузы, когда пользователь перестанет набирать текст.
Допустим, наш динамический список называется СписокКонтрагентов и мы хотим искать по колонке Наименование.
&НаКлиенте
Перем ТаймерПоиска;
Процедура ПолеПоискаПоНаименованиюПриИзменении(Элемент)
// Отменяем предыдущий таймер, если он был установлен
Если ТаймерПоиска <> Неопределено Тогда
ОчиститьТаймер(ТаймерПоиска);
КонецЕсли;
// Устанавливаем новый таймер для отложенного поиска
// Поиск будет выполнен через 0.5 секунды после последнего изменения поля
ТаймерПоиска = УстановитьТаймер(0.5, "ВыполнитьПоискПоНаименованию", Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьПоискПоНаименованию()
// Отменяем таймер после выполнения
ОчиститьТаймер(ТаймерПоиска);
ТаймерПоиска = Неопределено;
УстановитьОтборСпискаКонтрагентов();
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборСпискаКонтрагентов()
Перем ИмяКолонкиДляПоиска;
ИмяКолонкиДляПоиска = "Наименование"; // Имя колонки, по которой ищем
// Очищаем существующие элементы отбора, связанные с нашим полем поиска
Если Элементы.СписокКонтрагентов.Отбор.Элементы.Найти(ИмяКолонкиДляПоиска) <> Неопределено Тогда
Элементы.СписокКонтрагентов.Отбор.Элементы.Удалить(Элементы.СписокКонтрагентов.Отбор.Элементы.Найти(ИмяКолонкиДляПоиска));
КонецЕсли;
// Если поле поиска не пустое, добавляем новый элемент отбора
Если Не ПустаяСтрока(ТекстПоиска) Тогда
НовыйЭлементОтбора = Элементы.СписокКонтрагентов.Отбор.Элементы.Добавить(ИмяКолонкиДляПоиска);
НовыйЭлементОтбора.ВидСравнения = ВидСравнения.НачинаетсяС;
НовыйЭлементОтбора.Значение = ТекстПоиска;
НовыйЭлементОтбора.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Обработчик события ПриСозданииНаСервере: Если вы хотите, чтобы при открытии формы поле поиска было пустым и отбор не был установлен, убедитесь, что реквизит ТекстПоиска инициализирован пустой строкой, а также в процедуре ПриСозданииНаСервере очистите отбор, если он мог быть установлен ранее (например, при сохранении настроек формы).
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Инициализация реквизита поиска
ТекстПоиска = "";
// Очищаем отбор по нашей колонке при создании формы
УстановитьОтборСпискаКонтрагентов(); // Вызов без параметров, чтобы очистить
КонецПроцедуры
Этот подход более сложен, но может быть более гибким в некоторых сценариях, особенно если стандартный механизм отбора не полностью удовлетворяет требованиям. Суть заключается в том, чтобы динамически изменять текст запроса, лежащего в основе динамического списка, добавляя к нему условие поиска.
Создаем элемент формы и реквизит: Аналогично предыдущему способу, создаем на форме поле ввода ПолеПоискаПоНаименованию и реквизит формы ТекстПоиска типа Строка.
Обработчик события ПриИзменении: Также используем отложенный поиск с помощью таймера.
&НаКлиенте
Перем ТаймерПоискаЗапрос;
Процедура ПолеПоискаПоНаименованиюПриИзменении(Элемент)
Если ТаймерПоискаЗапрос <> Неопределено Тогда
ОчиститьТаймер(ТаймерПоискаЗапрос);
КонецЕсли;
ТаймерПоискаЗапрос = УстановитьТаймер(0.5, "ВыполнитьПоискИзменениемЗапроса", Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьПоискИзменениемЗапроса()
ОчиститьТаймер(ТаймерПоискаЗапрос);
ТаймерПоискаЗапрос = Неопределено;
УстановитьЗапросСпискаКонтрагентов();
КонецПроцедуры
Модификация запроса на сервере: В серверной процедуре мы будем формировать текст запроса для динамического списка, добавляя в него условие ПОДОБНО.
Важно помнить, что мы должны использовать параметры запроса для безопасной передачи значения поиска и предотвращения SQL-инъекций. Также следует предусмотреть, чтобы при пустом поле поиска запрос возвращался к исходному состоянию без условий.
&НаСервере
Процедура УстановитьЗапросСпискаКонтрагентов()
Перем ИсходныйТекстЗапроса;
// Исходный текст запроса, который обычно содержится в свойстве "ОсновнойЗапрос" или "ТекстЗапроса"
// динамического списка, но без WHERE условий, которые мы хотим добавлять динамически.
// Например:
ИсходныйТекстЗапроса = "ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Наименование КАК Наименование,
| Контрагенты.Код КАК Код
|ИЗ
| Справочник.Контрагенты КАК Контрагенты";
Перем ТекстУсловияПоиска;
ТекстУсловияПоиска = "";
Если Не ПустаяСтрока(ТекстПоиска) Тогда
ТекстУсловияПоиска = "ГДЕ Контрагенты.Наименование ПОДОБНО &ПараметрПоиска";
КонецЕсли;
// Формируем окончательный текст запроса
Элементы.СписокКонтрагентов.ТекстЗапроса = ИсходныйТекстЗапроса + Символы.ПС + ТекстУсловияПоиска;
// Устанавливаем параметр запроса, если условие поиска активно
Если Не ПустаяСтрока(ТекстПоиска) Тогда
Элементы.СписокКонтрагентов.УстановитьПараметр("ПараметрПоиска", ТекстПоиска + "%");
Иначе
// Важно очищать параметр, если он больше не используется
Элементы.СписокКонтрагентов.УстановитьПараметр("ПараметрПоиска", Неопределено);
КонецЕсли;
// Обновляем список, чтобы применились изменения запроса
Элементы.СписокКонтрагентов.Обновить();
КонецПроцедуры
Обработчик события ПриСозданииНаСервере: Убедимся, что при создании формы запрос динамического списка корректно инициализирован.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ТекстПоиска = "";
УстановитьЗапросСпискаКонтрагентов(); // Устанавливаем начальный запрос
КонецПроцедуры
В некоторых случаях может потребоваться не фильтрация списка, а именно перемещение курсора к найденному элементу, оставляя при этом остальные элементы видимыми. Этот вариант обычно сложнее в реализации для динамических списков, так как прямой доступ ко всем загруженным элементам списка для поиска на клиенте может быть ограничен, а постоянные обращения к серверу для поиска конкретного элемента могут быть неэффективны.
Если данные, отображаемые в списке, небольшие и могут быть полностью загружены на клиент, можно попробовать следующие шаги:
Полная загрузка данных: Загрузите все необходимые данные в коллекцию на стороне клиента (например, в ТаблицаЗначений или Массив).
Поле ввода и поиск: Создайте поле ввода, как в предыдущих примерах. В обработчике события ПриИзменении этого поля (снова с отложенным выполнением) осуществляйте поиск по загруженной клиентской коллекции.
Установка текущей строки: Если элемент найден в клиентской коллекции, попытайтесь установить его как текущий элемент в динамическом списке. Для этого вам потребуется найти ссылку на соответствующий объект, а затем использовать метод ТекущаяСтрока или УстановитьТекущуюСтроку для табличного поля.
&НаКлиенте
Процедура УстановитьТекущийЭлементСписка(ИскомаяСсылка)
Если ИскомаяСсылка = Неопределено Тогда
Возврат;
КонецЕсли;
Элементы.СписокКонтрагентов.ТекущаяСтрока = ИскомаяСсылка;
КонецПроцедуры
Важное замечание: Этот подход наименее рекомендован для динамических списков, так как он нарушает их основной принцип работы (частичная загрузка данных) и может привести к значительным проблемам производительности и большим расходам памяти при работе с большими объемами данных.
Мы выяснили, что "нативного" функционала поиска по первым символам в одной колонке динамического списка управляемых форм, аналогичного обычным формам, в платформе 1С:Предприятие 8.3 не существует. Для достижения подобного поведения требуются программные доработки.
Ctrl+F) и расширенного поиска (Alt+F). Иногда этого оказывается достаточно.Выбор конкретного решения будет зависеть от ваших специфических требований, объема данных и ожиданий пользователей. Наиболее часто применяемым и рекомендуемым подходом является создание отдельного поля ввода, которое управляет отбором динамического списка.