Предыстория
К написанию статьи меня подтолкнула задача, для решения которой я должен был разработать сложную форму с большим количеством полей, связанных с разными объектами и, что главное, «c одной кнопкой». Тут и родилась мысль воспользоваться функцией «ввода по строке» в управляемом приложении 1С. В процессе решения задачи пришлось «набить шишек», но, надеюсь, приобретенный опыт будет полезен не только мне.
Механика
Думаю, правильным будет начать с краткого описания механики клиент-серверного взаимодействия при «вводе по строке».
Все начинается с поля ввода формы, у которого есть события «Автоподбор» и «ПриОкончанииВводаТекста».
Событие «АвтоПодбор» возникает при остановке ввода текста или нажатии на кнопку «стрелка вниз».
Событие «ОкончаниеВводаТекста» вызывается, как нам сообщает справка, при формировании значения из текста ввода. Кстати, это событие интересно тем, что если значение не сформировано, система не даст нам выйти из режима редактирования элемента. Иными словами, если введенный в поле текст не соответствует какому либо значению из данных выбора, то редактирование не будет завершено.
Оба перечисленные события вызываются на стороне клиента. Это дает возможность поработать с данными выбора и с текстом, введенным в поле, но заменить данные выбора на какие-то другие, полученные с сервера, мы не сможем. Дело в том, что мы не имеем права вызывать для этих событий серверные методы с директивой компиляции &НаСервере . Об этом нас предупреждает синтаксис помощник, и ему стоит поверить. На самом деле, такой вызов и не приведет к исключению, но тонкая организация механизма будет нарушена, и мы получим нечто непригодное для использования.
Обращаясь к труду «Разработка управляемого интерфейса» госпожи Хрусталевой и прочих уважаемых авторов, находим упоминание о методе «ПолучитьДанныеВыбора». Если спросить об этом методе синтаксис помощник, он выдаст нам список методов менеджеров для всех видов объектов платформы. Но, что толку от методов менеджеров, которые выполняются на сервере, если серверные вызовы нам недоступны? На самом деле, этот вопрос здесь, только по той причине, что если бы я был более внимательным человеком, я сразу решил бы свою задачу, и никакой статьи не появилось бы. Достаточно просто пролистать до конца список ссылок, и в конце обнаружится глобальный метод «ПолучитьДанныеВыбора». С помощью этого метода мы на клиенте можем получить данные выбора для любого ссылочного объекта системы, что дает возможность переопределить стандартный алгоритм получения выбора данных. Например, для поля строчного типа, у которого вообще нет стандартных данных выбора, использовать алгоритм справочника «Контрагенты».
Но для нас основная ценность метода «ПолучитьДанныеВыбора» в том, что он провоцирует вызов события «ПриПолученииДанныхВыбора», котрое выполняется в контексте менеджера выбранного нами типа объекта. Иными словами мы, наконец, получаем возможность работать с сервером, а значит и самостоятельно сформировать данные выбора. И с этого момента на возможность работать с автоподбором влияют только фантазия и здравый смысл.
Задача
Мы разобрались с взаимодействием клиента и сервера, теперь я предлагаю подкрепить теорию практикой. Решим небольшую задачу, которая звучит следующим образом.
Дано:
- Демонстрационная конфигурация «Управляемое приложение»
- Покупатели «Компании» являются частными лицами
- Наименования клиентов по правилам «Компании» состоят из фамилии и инициалов.
- ФИО клиентов могут периодически изменяться
Реализовать в форме документа «РасходТовара» подбор покупателя по ФИО.
Решать сохранение нового покупателя и его ФИО не будем, так как к «вводу по строке» это не относится.
Решение:
Добавим в конфигурацию «Управляемое приложение» новый периодический регистр сведений «ФИОКонтрагентов». Периодичность «день», единственное и ведущее измерение «Контрагент» (Тип(«СправочникСсылка.Контрагенты»)), ресурсы «Фамилия», «Имя», «Отчество» (Тип(«Строка(50)»)).
На форме документа «РасходТовара» также добавим три новых реквизита «ПокупательФамилия», «ПокупательИмя», «ПокупательОтчество». Также, для удобства, добавим кнопку и команду «ОчиститьФИО».
&НаКлиенте
Процедура ОчиститьФИО(Команда)
Объект.Покупатель = Неопределено;
Фамилия = "";
Имя = "";
Отчество = "";
КонецПроцедуры
В модуле формы реализуем метод «ПолучитьДанныеВыбораПоФИО» с директивой компиляции &НаКлиенте
&НаКлиенте
Функция ПолучитьДанныеВыбораПоФИО(Элемент, ПокупательФамилия, ПокупательИмя, ПокупательОтчество, СтандартнаяОбработка)
// Выключим стандартную обработку
СтандартнаяОбработка = Ложь;
// Определим структуру для получения параметров отбора,
// так как стандартный выбор мы выключим значения структуры пусты
ПараметрыПодбора = Новый Структура("Отбор,СтрокаПоиска,ВыборГруппИЭлементов",
Новый Структура(), // Здесь можно установить отбор
"", // Передаем введенный в поле текст
ПредопределенноеЗначение("ИспользованиеГруппИЭлементов.Элементы"));
// Дополним стандартную структуру с дополнительными параметрами для поиска по ФИО
ПараметрыПодбора.Вставить("ДополнительныеПараметры", Новый Структура("Фамилия,Имя,Отчество,Дата",
ПокупательФамилия,
ПокупательИмя,
ПокупательОтчество,
Объект.Дата));
// Передаем ФИО и получаем список выбора
Возврат ПолучитьДанныеВыбора(Тип("СправочникСсылка.Контрагенты"), ПараметрыПодбора);
КонецФункции
В модуле менеджера справочника «Контрагенты» реализуем обработчик «ОбработкаПолученияДанныхВыбора»
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
Перем ДополнительныеПараметры;
Если Параметры.Свойство("ДополнительныеПараметры", ДополнительныеПараметры) Тогда
// Выключим стандартную обработку
СтандартнаяОбработка = Ложь;
ДанныеВыбора = РегистрыСведений.ФИОКонтрагентов.ПолучитьДанныеВыбораФИО(ДополнительныеПараметры.Фамилия,
ДополнительныеПараметры.Имя,
ДополнительныеПараметры.Отчество,
ДополнительныеПараметры.Дата);
КонецЕсли;
КонецПроцедуры
В модуле менеджера регистра сведений «ФИОКонтрагентов» реализуем экспортную функцию
«ПолучитьДанныеВыбораФИО»
Функция ПолучитьДанныеВыбораФИО(Знач Фамилия, Знач Имя, Знач Отчество, Период) Экспорт
спВыбора = Новый СписокЗначений;
// Подготовим шаблоны поиска по вхождению
Если НЕ ЗначениеЗаполнено(СокрЛП(Фамилия)) Тогда
Возврат Неопределено;
Иначе
Фамилия = СокрЛП(Фамилия) + "%";
КонецЕсли;
Имя = СокрЛП(Имя) + "%";
Отчество = СокрЛП(Отчество) + "%";
// Сформируем запрос в котором достаточно данных для наглядного представления контрагентов
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 50
| ФИОКонтрагентовСрезПоследних.Фамилия,
| ФИОКонтрагентовСрезПоследних.Имя,
| ФИОКонтрагентовСрезПоследних.Отчество,
| ФИОКонтрагентовСрезПоследних.Контрагент,
| ПРЕДСТАВЛЕНИЕССЫЛКИ(ФИОКонтрагентовСрезПоследних.Контрагент) КАК КонтрагентПредставление,
| ВЫРАЗИТЬ(ФИОКонтрагентовСрезПоследних.Контрагент КАК Справочник.Контрагенты).Код КАК КонтрагентКод
|ИЗ
| РегистрСведений.ФИОКонтрагентов.СрезПоследних(&Период, ) КАК ФИОКонтрагентовСрезПоследних
|ГДЕ
| ФИОКонтрагентовСрезПоследних.Фамилия ПОДОБНО &Фамилия
| И ФИОКонтрагентовСрезПоследних.Имя ПОДОБНО &Имя
| И ФИОКонтрагентовСрезПоследних.Отчество ПОДОБНО &Отчество";
Запрос.УстановитьПараметр("Период", Период);
Запрос.УстановитьПараметр("Фамилия", Фамилия);
Запрос.УстановитьПараметр("Имя", Имя);
Запрос.УстановитьПараметр("Отчество", Отчество);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ПредставлениеКонтрагента = Выборка.Фамилия;
Если ЗначениеЗаполнено(Выборка.Имя) Тогда
ПредставлениеКонтрагента = ПредставлениеКонтрагента + " " + Выборка.Имя;
КонецЕсли;
Если ЗначениеЗаполнено(Выборка.Отчество) Тогда
ПредставлениеКонтрагента = ПредставлениеКонтрагента + " " + Выборка.Отчество;
КонецЕсли;
ПредставлениеКонтрагента = ПредставлениеКонтрагента + "(" + Выборка.КонтрагентКод +":" + Выборка.КонтрагентПредставление + ")";
спВыбора.Добавить(Выборка.Контрагент,
ПредставлениеКонтрагента);
КонецЦикла;
Возврат спВыбора;
КонецФункции // ПолучитьДанныеВыбораФИО()
Теперь определим в форме документа обработчики «ФамилияАвтоПодбор», «ИмяАвтоПодбор», «ОтчествоАвтоПодбор».
&НаКлиенте
Процедура ФамилияАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, Ожидание, СтандартнаяОбработка)
// Если в уже заполненом текстовом поле нажать "вниз", то параметр "Текст" окажется пустым
// учтем это
знТекст = ?(ПустаяСтрока(Текст), Фамилия, Текст);
ДанныеВыбора = ПолучитьДанныеВыбораПоФИО(Элемент, знТекст, Имя, Отчество, СтандартнаяОбработка);
КонецПроцедуры
&НаКлиенте
Процедура ИмяАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, Ожидание, СтандартнаяОбработка)
знТекст = ?(ПустаяСтрока(Текст), Имя, Текст);
ДанныеВыбора = ПолучитьДанныеВыбораПоФИО(Элемент, Фамилия, знТекст, Отчество, СтандартнаяОбработка);
КонецПроцедуры
&НаКлиенте
Процедура ОтчествоАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, Ожидание, СтандартнаяОбработка)
знТекст = ?(ПустаяСтрока(Текст), Отчество, Текст);
ДанныеВыбора = ПолучитьДанныеВыбораПоФИО(Элемент, Фамилия, Имя, знТекст, СтандартнаяОбработка);
КонецПроцедуры
Обработчики «ФИООбработкаВыбора» , «ФИОПриИзменении», «ФИОПриИзмененииНаСервере» подойдут для всех полей ФИО.
&НаКлиенте
Процедура ФИООбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Объект.Покупатель = ВыбранноеЗначение;
КонецПроцедуры
&НаКлиенте
Процедура ФИОПриИзменении(Элемент)
ФИОПриИзмененииНаСервере(Элемент.Имя);
// Обработаем изменение "Покупателя"
ПокупательПриИзменении(Элементы.Покупатель);
КонецПроцедуры
&НаСервере
Процедура ФИОПриИзмененииНаСервере(ИмяЭлемента)
// Если выбор сделан, то заполним поля ФИО
Если ЗначениеЗаполнено(Объект.Покупатель) Тогда
текФИО = ПолучитьФИОКонтрагента();
//Если элемент содержит пустую строку, то мы ищем нового покупателя
Если ПустаяСтрока(ЭтаФорма[ИмяЭлемента])
И НЕ ПустаяСтрока(текФИО[ИмяЭлемента]) Тогда
Объект.Покупатель = Неопределено;
Иначе
ЗаполнитьЗначенияСвойств(ЭтаФорма, текФИО);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Готово! Можем заходить и проверять, что у нас получилось.
Решенный вариант можно получить с помощью обновления (cfu) в приложении к статье. Для этого создайте из "Демонстрационной конфигурации "Управляемое приложение" (1.0.16.1)" файл поставки и обновите его приложенным файлом. Для тех, кто редко делает поставки вот нехитрая процедура:
- Получите на users.v8.1c.ru демонстрационную конфигурацию 1.0.16.1 в разделе «Технологическая платформа 8.3/Демонстрационная информационная база»
- Установите
- Запустите конфигуратор с демонстрационной конфигурацией
- Выберите в меню «Конфигурация»/ «Поставка конфигурации»/ «Создать файлы поставки и обновления конфигурации»
- Уберите «Создать файл обновления конфигурации»
- Нажмите «Выполнить»
- Загрузите полученный файл поставки в информационную базу: «Конфигурация»/ «Загрузить конфигурацию из файла»
- Обновите поставку файлом, приложенным к статье: «Конфигурация»/ «Поддержка»/ «Обновить конфигурацию»/ «Выбор файла обновления»/ «Далее» /Выбираем и файл и обновляем.
- Сохраните конфигурацию и запустите информационную базу
- Задавайте вопросы и конструктивно критикуйте.
P.S. Хочу напомнить, что выход из режима «подбора по строке» без выбора осуществляется через “Esc”, табуляция по умолчанию принимает текущую строку как выбор.