Ввод по строке (переопределение)

Опубликовал Николай С (niko11s) в раздел Программирование - Практика программирования

Предлагаю простое решение, которое позволяет сделать ввод по строке более удобным для пользователя.

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

А именно было необходимо, чтобы система искала нужную номенклатуру, при наборе с клавиатуры не только по первым символам (это стандартное поведение), но и по вхождению введенных символов в название.  

 

Рассмотрим пример. Допустим, есть список номенклатуры, в котором есть - газета "Ярмарка":

Если мы начинаем набор со слова "газета", система нам находит нужную позицию. Совсем другое дело, если мы не помним точно, как у нас записана нужная номенклатура и, допустим, начинаем ввод со слова "Ярмарка". В этом случае система не сможет найти нужную нам позицию:

Решить данную задачу нам поможет обработчик модуля менеджера - ОбработкаПолученияДанныхВыбора().

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

Итак, обращаемся к модулю менеджера справочника "Номенклатура":

 Контекс выполнения этой процедуры - это "сервер", поэтому в получении нужного нам списка мы сможем использовать запрос. В реализации нашей задачи нам поможет оператор запроса "ПОДОБНО" и определенная маска для наименования:

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

	
КонецПроцедуры
 

 Отметим, что в нашем обработчике - ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбраблтка) для нас важны все три параметра. В первый "ДанныеВыбора" мы загружаем наш список номенклатуры, полученный по нашему алгоритму. Из параметра "Параметры" мы получим значение введенное пользователем, а третьему параметру "СтандартнаяОбработка" мы должны поставить значение "Ложь"(отключаем стандартный алгоритм системы).

В результате одной небольшой процедурой мы полностью решили поставленную задачу:

 Данный способ решиния задачи я использовал еще на Платформе 2.0. Как подсказали в комментариях коллеги в Платформе 3.0 задача решается ещё проще. В справочнике на закладке "Поле ввода" можно выбрать режим ввода по строке. Там два варианта: "начало" и "любая часть". 

      Однако описанный в статье способ использования обработчика модуля менеджера - ОбработкаПолученияДанныхВыбора() хорошо подойдет, если понадобится другой вариант работы алгоритма ввода по строке, ну или если у Вас все ещё платформа 8.2.

См. также

Комментарии
1. blindcat2006 (blindcat2006) 62 10.09.15 07:41 Сейчас в теме
Прикольно, наверное, но... (см картинку)
Хотя если для других вариантов использовать - для новичков пойдет
Прикрепленные файлы:
Magnastrag; Aleksey.Bochkov; NeviD; dj_serega; BigB; FullMoon; niko11s; anig99; ojiojiowka; superkuzja; mmoozzgg; +11 Ответить 2
2. Александр Медведев (anig99) 2512 10.09.15 09:06 Сейчас в теме
(1) blindcat2006, Чутка подправить статью и будет годна. То, что на картинке, появилось только в 8.3, а ОбработкаПолученияДанныхВыбора есть уже в 8.2 на управляемых формах.
3. Валерий К (klinval) 198 10.09.15 12:49 Сейчас в теме
Данный способ решиния задачи я использовал еще на Платформе 2.0. Как подсказали в комментариях коллеги в Платформе 3.0 задача решается ещё проще.

Платформа 2.0 и 3.0? Может платформа 8.2 и 8.3 или конфигурация Бухгалтерия предприятия 2.0 и 3.0? Когда работал во франче у нас менеджеры так путались, не думал, что программист может также запутаться...
Сама публикация нормальная, правда я уже давно на платформе 8.3 сижу, поэтому вряд ли мне понадобится данные в публикации наработки.
cleaner_it; BigB; pt_olga; +3 Ответить 1
4. Николай С (niko11s) 250 10.09.15 13:06 Сейчас в теме
5. Игорь Фелькер (Brawler) 292 10.09.15 13:12 Сейчас в теме
стоило бы ограничить число строк возвращаемых запросом
6. Денис Карпов (dtripleh) 10.09.15 14:24 Сейчас в теме
Зачем это всё, когда в платформе реализован ввод по строке по любой части?

p.s Понял. Недочитал:)
7. Антон Антонов (monkbest) 28 11.09.15 10:12 Сейчас в теме
Есть минусы:
1. Производительность. номенклатура - справочник содержащий тысячи позиций даже в небольшой фирме. Выражение ПОДОБНО - медленное по сравнению с вырезанием первых n символов. Я бы сначала проанализировал длину строки поиска и допустим искал бы от 3ех или 4ех символов, если введен 1 символ или два отказ = истина. Еще бы добавил в запрос Выбрать первые 5-6, т.к. больше в список выбора один фиг не поместится
2. Вы убили поиск по коду и артикулу. В ЗУП 3.0 в свое время убили ввод сотрудника по табельному т.к. косячно запрос написали. Т.е. они учли поиск по табельному, но сравнивали табельный с кодом физ.лица а не сотрудника :) у Вас это вообще не учтено. Т.е. надо писать столько условий ПОДОБНО через ИЛИ, сколько у Вас полей используется для ввода по строке. Универсально будет пройтись по метаданным справочника и кодом сгенерить текст условия по всем полям. Это позволит в дальнейшем, если кто добавит еще один реквизит для ввода по строке, он не будет ломать мозг почему не работает, пока не найдет Вашу процедуру.

TreeDogNight; kostyaomsk; Рамзес; IgorS; ivanov660; BigB; +6 Ответить
8. Михаил Андрияшкин (mickey.1cx) 26 11.09.15 14:59 Сейчас в теме
Где то месяц назад мне потребовался ввод по строке с поиском по реквизитам справочника, включая неограниченные строковые.
Реализовал через полнотекстовый поиск, из плюсов - произвольный порядок слов
при вводе по строке.
hafgwkvs; +1 Ответить
9. Ильдар Тагиров (pentanom) 10 16.09.15 11:42 Сейчас в теме
(1) blindcat2006, А у меня почему-то это не работает :(
Конфигурация 11.1.10.180
Платформа 8.3.6.2152
10. Вадим Никонов (V.Nikonov) 113 16.09.15 12:22 Сейчас в теме
Данный принцип позволит искать элементы по специфичным данным, не являющихся реквизитами элементов! Например, искать Контрагента по номеру телефона (регистр, Контактные данные) и тому подобное... Вводимая подстрока может быть свойством, родителем или тем чем требуется. Подстрока поиска может быть подвержена транслитерации, замене раскладки и т.д.
Автору +
йцукенг; +1 Ответить
11. Vadim Kovyrshin (vdmkvrshn) 13 11.03.17 17:53 Сейчас в теме
Хорошее решение, пользователям такой поиск нравится. Только вот ничего новаторского в нем нет, т.к. это сделано в типовой УТ11, например,в справочниках Партнеров, Номенклатуры и может еще где-то. Я его переделал, расширив поиском по данным контактной информации партнеров, контрагентов, контактных лиц партнеров. А также сделал выделение найденного фрагмента строки цветом, как это работает при стандартном поиске платформой. Вот могу показать фрагментно основные куски кода:


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

		Запрос.Текст = ПолучитьТекстЗапросаПоиска(Параметры.СтрокаПоиска, СтрокаОтбора);
		Параметры.СтрокаПоиска = СтрЗаменить(СокрЛП(Параметры.СтрокаПоиска), " ", "%");
		Если Лев(Параметры.СтрокаПоиска, 1) = "@" Тогда
			Параметры.СтрокаПоиска = Прав(Параметры.СтрокаПоиска, СтрДлина(Параметры.СтрокаПоиска) - 1);
		КонецЕсли;
		
		Запрос.УстановитьПараметр("СтрокаВвода",Параметры.СтрокаПоиска + "%" );

		Выборка = Запрос.Выполнить().Выбрать();
		
		СформироватьСписокВыбораДляПоляВводаСправочника(ДанныеВыбора, Выборка, Параметры);
КонецПроцедуры

Функция ПолучитьТекстЗапросаПоиска(ПоисковаяСтрока, СтрокаОтбора)
	
	ПоискПоАдресамЭП = Лев(ПоисковаяСтрока, 1) = "@";
	ПоискНомерам = Найти("0123456789", Лев(ПоисковаяСтрока, 1)) > 0;
	
	ТекстЗапроса = 
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ ПЕРВЫЕ 0
	|	ЗНАЧЕНИЕ(Справочник.Партнеры.ПустаяСсылка) КАК Ссылка,
	|	"""" КАК Представление,
	|	ЛОЖЬ КАК ПометкаУдаления,
	|	"""" КАК ЗначениеПоля,
	|	"""" КАК НайденоПо
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|";
	
	Если ПоискПоАдресамЭП Тогда
		ТекстЗапроса = ТекстЗапроса + 
		"ВЫБРАТЬ ПЕРВЫЕ 20
		|	Партнеры.Ссылка,
		|	ПРЕДСТАВЛЕНИЕ(Партнеры.Ссылка),
		|	Партнеры.ПометкаУдаления,
		|	ПартнерыКонтактнаяИнформация.Представление,
		|	""НайденоПоКИ""
		|ИЗ
		|	Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Партнеры КАК Партнеры
		|		ПО ПартнерыКонтактнаяИнформация.Ссылка = Партнеры.Ссылка
		|			И (ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
		|ГДЕ
		|	ПартнерыКонтактнаяИнформация.Представление ПОДОБНО &СтрокаВвода
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ ПЕРВЫЕ 20
		|	Партнеры.Ссылка,
		|	ПРЕДСТАВЛЕНИЕ(Партнеры.Ссылка),
		|	Партнеры.ПометкаУдаления,
		|	КонтрагентыКонтактнаяИнформация.Представление,
		|	""НайденоПоКИ""
		|ИЗ
		|	Справочник.Контрагенты.КонтактнаяИнформация КАК КонтрагентыКонтактнаяИнформация
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Партнеры КАК Партнеры
		|		ПО КонтрагентыКонтактнаяИнформация.Ссылка.Партнер = Партнеры.Ссылка
		|			И (КонтрагентыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
		|ГДЕ
		|	КонтрагентыКонтактнаяИнформация.Представление ПОДОБНО &СтрокаВвода
                // ...............................
                ";
КонецФункции

// Процедура - Сформировать список выбора для поля ввода справочника
//
// Параметры:
//  ДанныеВыбора			 - Неопределено - Параметр для возврата заполненного списка значений выбора
//  ВыборкаРезультатаЗапроса - ВыборкаИзРезультатаЗапроса - Выборка из результата запроса с полями "Ссылка, Представление, ПометкаУдаления, ЗначениеПоля, НайденоПо"
//  Параметры				 - Структура - Параметры из обработчика события ОбработкаПолученияДанныхВыбора
//
Процедура СформироватьСписокВыбораДляПоляВводаСправочника(ДанныеВыбора, Выборка, Параметры) Экспорт // + Ковыршин В.С. 07.02.2017
	
	Если Выборка.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеВыбора = Новый СписокЗначений;
	
	ЧастиСтрокиПоиска = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(Параметры.СтрокаПоиска, "%", Истина, Истина);
	СоздаватьПростойСписок = Ложь;
	Если Параметры.Свойство("СоздаватьПростойСписок") И Параметры.СоздаватьПростойСписок = Истина Тогда
		СоздаватьПростойСписок = Истина;
	КонецЕсли;
	
	КэшСсылок = Новый Соответствие;
	Пока Выборка.Следующий() Цикл
		
		Если Не КэшСсылок[Выборка.Ссылка] = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		КэшСсылок[Выборка.Ссылка] = Выборка.ЗначениеПоля;
		
		ЗначениеПоля = Выборка.ЗначениеПоля;
		ФорматированныеСтроки = Новый Массив;
		Для Каждого ЧастьСтрокиПоиска Из ЧастиСтрокиПоиска Цикл
			НачалоВхождения = Найти(ВРег(ЗначениеПоля), ВРег(ЧастьСтрокиПоиска));
			Если НачалоВхождения > 1 Тогда
				ФорматированныеСтроки.Добавить(Лев(ЗначениеПоля, НачалоВхождения - 1));
				ЗначениеПоля = Прав(ЗначениеПоля, СтрДлина(ЗначениеПоля) - НачалоВхождения + 1);
			КонецЕсли;
			ФорматированныеСтроки.Добавить(Новый ФорматированнаяСтрока(Лев(ЗначениеПоля, СтрДлина(ЧастьСтрокиПоиска)), Новый Шрифт(,,Истина), ЦветаСтиля.ЦветТекстаУспех));
			ЗначениеПоля = Прав(ЗначениеПоля, СтрДлина(ЗначениеПоля) - СтрДлина(ЧастьСтрокиПоиска));
		КонецЦикла;
		
		Если СтрДлина(ЗначениеПоля) > 0 Тогда
			ФорматированныеСтроки.Добавить(ЗначениеПоля);
		КонецЕсли;
		
		Если Не Выборка.НайденоПо = "НайденоПоНаименованию" Тогда
			ФорматированныеСтроки.Добавить(" (" + Выборка.Представление + ")");
		КонецЕсли;
		ТекстПредставление = Новый ФорматированнаяСтрока(ФорматированныеСтроки);
		
		Если Не СоздаватьПростойСписок И Выборка.ПометкаУдаления Тогда
			СтруктураЗначение = Новый Структура("Значение,ПометкаУдаления", Выборка.Ссылка, Выборка.ПометкаУдаления);
			ДанныеВыбора.Добавить(СтруктураЗначение, ТекстПредставление, , БиблиотекаКартинок.ПомеченныйНаУдалениеЭлемент);
		Иначе
			ДанныеВыбора.Добавить(Выборка.Ссылка, ТекстПредставление);
		КонецЕсли;
	КонецЦикла;
		
КонецПроцедуры


...Показать Скрыть
Оставьте свое сообщение