Добавление функционала "поиск по строке" для динамического списка управляемого приложения на основе Подбора в УНФ

26.10.12

Разработка - Механизмы платформы 1С

Пример реализации "поиска по строке" для любой колонки динамического списка управляемого приложения на основе использования Отбора и сортировки списка.

Одним из  неприятных моментов при работе с динамическими списками управляемого приложения является невозможность  использования такой привычной для  обычного приложения опции, как «поиск по строке».  Предлагаю один из вариантов реализации поиска по первым буквам  в динамическом списке на основе общей Формы Подбора из типовой конфигурации УНФ.

В описанном ниже примере поиск  вместе с сортировкой по полю реализован для колонок Код, Артикул, Наименование.

Добавляем  Реквизиты формы ПоискКод, ПоискАртикул, ПоискНаименование с типом «Строка».Вносим их в Группу Поиск на форме.

Программируем  события поля ввода АвтоПодбор:

поле ввода ПоискАртикул

 

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

 процедура
Установитьпорядок(ИмяПоля)
     Если НЕ (
СписокЗапасов.Порядок.элементы.количество() = 1 и СписокЗапасов.Порядок.элементы[0].поле = Новый ПолеКомпоновкиДанных(ИмяПоля))  тогда
        
СписокЗапасов.Порядок.элементы.очистить();
        
НЭлемент = СписокЗапасов.Порядок.Элементы.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
        
НЭлемент.Использование = Истина;
        
НЭлемент.Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);
        
НЭлемент.ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных.Возр;
        
НЭлемент.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный;
     конецЕсли;
 КонецПроцедуры

&НаСервере
Процедура УстановитьПоискПоСтрокеНаСервере(Текст, ИмяКолонки)
    
ПостроительЗапроса = новый построительЗапроса;
    
ПостроительЗапроса.Текст = "ВЫБРАТЬ
                                |   Номенклатура.Ссылка
                                |ИЗ
                                |   Справочник.Номенклатура КАК Номенклатура
                                |ГДЕ
                                |   ПОДСТРОКА(Номенклатура."
+ ИмяКолонки + " , 1, &Длина) = &Зн
                                |{ГДЕ
                                |   Номенклатура.Ссылка.*}"
;
   
ПостроительЗапроса.Параметры.Вставить("Длина", СтрДлина(Текст));
   
ПостроительЗапроса.Параметры.Вставить("Зн", Текст);

    Если Не
СписокЗапасов.Параметры.элементы[2].Значение = Справочники.Номенклатура.ПустаяСсылка() тогда
       
НЭлемент = ПостроительЗапроса.Отбор.Добавить("Ссылка");
       
НЭлемент.ВидСравнения = ВидСравнения.ВИерархии;
       
НЭлемент.Значение = СписокЗапасов.Параметры.элементы[2].Значение;
       
НЭлемент.Использование = Истина;
    КонецЕсли;
   
ПостроительЗапроса.Выполнить();
   
ТЗ = Построительзапроса.Результат.Выгрузить();
   
Сп = новый СписокЗначений;
   
Сп.ЗагрузитьЗначения(ТЗ.ВыгрузитьКолонку("Ссылка"));

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

&НаКлиенте
Процедура ПоискАртикулОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, СтандартнаяОбработка)
   
// Вставить содержимое обработчика.
   
Этаформа.ТекущийЭлемент = Элементы.СписокЗапасов;
КонецПроцедуры

Таким образом получаем , что при наборе первых букв искомого варианта в поле «по артикулу» , например,  группы поиска,  происходит сортировка списка по колонке Артикул и отбор тех строк, артикул которых начинается с набранных символов. 

результат работы кода

Тут , конечно, был бы удачнее не отбор, а позиционирование на первом найденном в списке элементе .  Т.е.  мне бы хотелось в тексте запроса Построителя  добавить «Первые 1» и дальше просто позиционироваться на найденной ссылке, но как найти позицию в динамическом списке ? Ответа на этот вопрос  не нашла.

Буду рада любым предложениям по оптимизации этого варианта решения вопроса или ссылкам на другой вариант решения.

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4531    dsdred    53    

72

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5294    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6410    dsdred    36    

112

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18475    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12088    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8822    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6279    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15986    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. mozz 148 24.04.13 15:51 Сейчас в теме
Моя реализация (можно искать по фрагментам наименования):
Добавляем текстовый реквизит СтрокаПоиска команду ПоказатьВсе (если нашли больше 50 элементов, то выводим 50 и если пользователь хочет то все остальные) и текстовую декорацию ПредупреждениеПоиск

Использованы в том числе и Ваши идеи.

Это в форме подбора:
&НаКлиенте
Процедура ОткючитьФильтр(Элемент, СтандартнаяОбработка)
	СписокЗапасов.Отбор.Элементы.Очистить();
	Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.ИерархическийСписок;
	Элементы.ПредупреждениеПоиск.Заголовок = "";
	СтрокаПоиска = "";
	Элементы.ПоказатьВсе.Видимость = Ложь;
КонецПроцедуры

//По результатам запроса при необходимости заполняем список выбора, таблицу выбора
&НаСервере
Процедура СделатьВыбор(СписокФрагментов, Первые = "") 
	//Получаем таблицу с найденными элементами
	ТаблицаРезультата = ОбщегоНазначенияВызовСервера.РезультатЗапросаПоиска(СписокФрагментов, "Номенклатура", Первые);
	Если ТаблицаРезультата.Количество() = 50 Тогда 
		Элементы.ПредупреждениеПоиск.Заголовок = "Показаны первые 50 !!!";
		Элементы.ПоказатьВсе.Видимость = Истина;
	Иначе
		Элементы.ПредупреждениеПоиск.Заголовок = "Найдено всего "+ТаблицаРезультата.Количество()+" записей";
		Элементы.ПоказатьВсе.Видимость = Ложь;
	КонецЕсли;
	//ОчиститьСписки();
	СписокЗапасов.Отбор.Элементы.Очистить();
	//Имеем три варианта: 
	//Элементы не найдены
	Если ТаблицаРезультата.Количество() = 0 Тогда
		Элементы.СтрокаПоиска.ЦветФона = Новый Цвет(255, 216, 128);
	//Найден один элемент, что и требовалось. Теперь уходим отсюда.
	ИначеЕсли ТаблицаРезультата.Количество() = 1 Тогда
		Элементы.СтрокаПоиска.ЦветФона = Новый Цвет(240, 255, 240);
		СтрокаПоиска = ТаблицаРезультата[0].Наименование;
		УстановитьОтборПоНайденному(ТаблицаРезультата);
	//Найдено много элементов
	Иначе
		Элементы.СтрокаПоиска.ЦветФона = Новый Цвет(255, 255, 255);
		КоличествоНайденныхЭлементов = ТаблицаРезультата.Количество();
		УстановитьОтборПоНайденному(ТаблицаРезультата);
	КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура УстановитьОтборПоНайденному(ТаблицаРезультата)
	Сп = новый СписокЗначений;
    Сп.ЗагрузитьЗначения(ТаблицаРезультата.ВыгрузитьКолонку("Ссылка"));

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

&НаКлиенте
Процедура ПоказатьВсеНажатие(Элемент)
	
	ТекстПоиска = СокрЛП(Элементы.СтрокаПоиска.Значение);
	Элементы.СтрокаПоиска.ЦветФонаПоля = Новый Цвет(255, 255, 255);
	//Менее двух символов за запрос не считаем
	Если СтрДлина(ТекстПоиска) < 2 Тогда
		//ОчиститьСписки();
		Возврат;
	КонецЕсли;
	//Составим список из набранных фрагментов
	СписокФрагментов = Новый СписокЗначений;
	МестоПробела = 1;
	Пока МестоПробела > 0 Цикл
		МестоПробела = Найти(ТекстПоиска, " ");
		Если МестоПробела > 0 Тогда 
			СписокФрагментов.Добавить(Лев(ТекстПоиска, МестоПробела - 1));
			ТекстПоиска = СокрЛП(Прав(ТекстПоиска, СтрДлина(ТекстПоиска) - МестоПробела));
		Иначе
			СписокФрагментов.Добавить(СокрЛП(ТекстПоиска));
		КонецЕсли;
	КонецЦикла;
	// отключим иерархический просмотр есличё...
	Если Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.ИерархическийСписок или Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.Дерево тогда
		Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.Список;
	КонецЕсли;
	
	СделатьВыбор(СписокФрагментов);
КонецПроцедуры

&НаКлиенте
Процедура СтрокаПоискаАвтоПодбор(Элемент, Текст, ДанныеВыбора, Ожидание, СтандартнаяОбработка)
	СтрокаПоиска = СокрЛП(Текст); 
	ТекстПоиска = СокрЛП(Текст);
	Элементы.СтрокаПоиска.ЦветФона = Новый Цвет(255, 255, 255);
	//Менее двух символов за запрос не считаем
	Если СтрДлина(ТекстПоиска) < 2 Тогда
		//ОчиститьСписки();
		Возврат;
	КонецЕсли;
	//Составим список из набранных фрагментов
	СписокФрагментов = Новый СписокЗначений;
	МестоПробела = 1;
	Пока МестоПробела > 0 Цикл
		МестоПробела = Найти(ТекстПоиска, " ");
		Если МестоПробела > 0 Тогда 
			СписокФрагментов.Добавить(Лев(ТекстПоиска, МестоПробела - 1));
			ТекстПоиска = СокрЛП(Прав(ТекстПоиска, СтрДлина(ТекстПоиска) - МестоПробела));
		Иначе
			СписокФрагментов.Добавить(СокрЛП(ТекстПоиска));
		КонецЕсли;
	КонецЦикла;
	// отключим иерархический просмотр есличё...
	Если Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.ИерархическийСписок или Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.Дерево тогда
		Элементы.СписокЗапасов.Отображение = ОтображениеТаблицы.Список;
	КонецЕсли;
	СделатьВыбор(СписокФрагментов,"ПЕРВЫЕ 50");
КонецПроцедуры

Показать


А это в общем модуле ОбщегоНазначенияВызовСервера

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

//Параллельно кириллице будем искать фрагменты на латинице,
//в двух вариантах из-за различия транслитирации некоторых букв
Функция Транслит(Фрагмент)
	СписокТранслита = Новый СписокЗначений;
	Кириллица = "абвгдежзийклмнопрстуфхц";               
	Латиница1 = "abvgdegzijklmnoprstufhc";
	Латиница2 = "abwgdejzijqlmnoprstufhc";
	КириллицаДиграф = "ч ш ";                                                  
	ЛатиницаДиграф = "chsh"; 
	Транслит1 = "";
	Транслит2 = "";
	Для позиция = 1 По СтрДлина(Фрагмент) Цикл
		текБуква = Сред(Фрагмент, позиция, 1);
		вШаблоне = Найти(Кириллица, текБуква);
		Если вШаблоне > 0 Тогда
			Транслит1 = Транслит1 + Сред(Латиница1, вШаблоне, 1);
			Транслит2 = Транслит2 + Сред(Латиница2, вШаблоне, 1);
			Продолжить;
		КонецЕсли;
	    вШаблоне = Найти(КириллицаДиграф, текБуква);
		Если вШаблоне > 0 Тогда
			Транслит1 = Транслит1 + Сред(ЛатиницаДиграф, вШаблоне, 2);
			Транслит2 = Транслит2 + Сред(ЛатиницаДиграф, вШаблоне, 2);
			Продолжить;
		КонецЕсли;
		Транслит1 = Транслит1 + текБуква;
		Транслит2 = Транслит2 + текБуква;
	КонецЦикла;
	СписокТранслита.Добавить(Транслит1);
	СписокТранслита.Добавить(Транслит2);
	Возврат СписокТранслита;	
КонецФункции
Показать
user591389_aska_rabota; +1 Ответить
2. dentoma51 8 11.12.13 15:26 Сейчас в теме
AlenaSa,благодарю Вас! Я воспользовался Вашей разработкой функционала "Поиск по строке".
Не знаю,может не правильно,но сделал так. В УФ добавил группу Поиск с симвоьным полем для ввода фрагмента наименования.

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

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

ПостроительЗапроса.Параметры.Вставить("Зн", "%"+Текст+"%");

ПостроительЗапроса.Выполнить();
ТЗ = Построительзапроса.Результат.Выгрузить();
Сп = новый СписокЗначений;
Сп.ЗагрузитьЗначения(ТЗ.ВыгрузитьКолонку("Ссылка"));

Список.Отбор.Элементы.Очистить();
НЭлемент = Список.Отбор.Элементы.добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Нэлемент.левоеЗначение = новый ПолекомпоновкиДанных("Контрагент");
НЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
НЭлемент.ПравоеЗначение = Сп;
НЭлемент.Использование = истина;
КонецПроцедуры


Вроде бы работает. Учитывая,что УФ только начинаю изучать,то рад и этому. Спасибо.
3. AlenaSa 30 11.12.13 21:45 Сейчас в теме
Спасибо всем за комментарии. Рада, что пригодилась публикация и есть развитие идеи.
Сама сейчас вернулась к УПП, которое ещё на обычном приложении.
УНФ не пользуется пока что на Украине популярностью, хотя мне очень понравилась, когда изучала и предлагала клиентам.
Оставьте свое сообщение