В продолжении статьи Пользовательский выбор из справочника. Часть1 хочу рассказать как можно без использовании функции SelectFromReferenceAction() переопределить пользовательский выбор из справочника. Конечно, удобнее и проще использовать для этого вышеназванную функцию, но все же есть ситуации, когда этого не получится, например:
● введенное значение нужно искать не только в наименовании, но и среди других реквизитов;
● нужно выбирать из таких системных справочников как Типы справочников, Отчеты и т.д.
Что же делать в этом случае?!
Для начала определим те условия, которые должны выполняться при выборе (функция SelectFromReferenceAction() им полностью соответствует):
● при очистке значения реквизита справочник не вызывается;
● при нажатии на клавишу
● при повторном выборе из справочника указатель записи устанавливается на ту запись, которая уже выбрана;
● при нажатии на комбинацию клавиш
● если отменили выбор из справочника, то восстанавливается прежнее значение реквизита;
● если при поиске по введенной строке обнаружилась единственная подходящая запись, то выбрать эту запись и не открывать окно справочника.
Напомню, что в вычислении «Выбор из справочника» есть предопределенные реквизиты, которые будем использовать в коде:
● SelectMode - тип выбора из справочника, принимает значения:
● smSelect – показ формы-списка;
● smLike – показ формы-списка только с теми записями, которые удовлетворяют введенным в поле данным;
● smCard – показ формы-карточки для введенного в поле значения.
● InputValue - текст, введенный в управляющий элемент, который связан с реквизитом.
● Requisite – ссылка на реквизит типа IRequisite, событие Выбор из справочника которого переопределяем.
В зависимости от значений этих реквизитов нужно показать карточку записи, показать форму-список справочника, показать форму-список только с теми записями, которые удовлетворяют введенным в поле данным или ничего не делать.
Вот небольшой пример, того как при выборе работника искать не только по наименованию, но и по должности:
if Assigned(InputValue) or (SelectMode <> smLike)
EmplRefFactory = References.РАБ
// Если нажали сочетание Ctrl+F4 для открытия карточки записи
if SelectMode = smCard
// Показать карточку
EmplRec = EmplRefFactory.GetObjectByCode(Requisite.Value)
EmplRec.Form.Show
else
WhereStr = ''
// Если в поле ввели значение и нажали Enter, то найти записи,
// удовлетворяющие введенному значению, искать в наименовании и в должности
if Assigned(InputValue) and (SelectMode = smLike)
WhereStr = PreprocQuery(Format('
(!РАБ!.!РАБ.Наименование! like "%%%0:s%%" or
!РАБ!.!РАБ.Строка! like "%%%0:s%%")';
// Заменить пробелы, чтобы искать по словосочетанию
Replace(InputValue; ' '; '%')))
endif
EmplRef = EmplRefFactory.GetComponent()
AddWhere = EmplRef.AddWhere(WhereStr)
EmplRef.Open
// Если подходит только 1 запись, то сразу заполнить поле, не показывая форму-список справочника
if (SelectMode = smLike) and (EmplRef.RecordCount = 1)
Requisite.Value = EmplRef.SYSREQ_CODE
else
// Показать форму-список справочника
// Если повторно выбирают запись, то указатель должен быть установлен на выбранной ранее записи
View = EmplRef.CreateView(EmplRef.MainViewCode)
if Assigned(Requisite.Value)
EmplRef.Rules.Rules(SET_FIRST_RECORD_IN_LIST_FORM_RULE_ID).Enabled =
not EmplRef.Locate(SYSREQ_CODE; Requisite.Value)
EmplRef.Refresh
endif
View.ViewMode = vmSelect
View.MultiSelection = FALSE
View.MainForm.Show
if View.MainForm.Result = mrOK
// Сохранить выбранное значение
EmplID = View.SelectedRecordsID(0)
Requisite.Value = КодПоAnalit(EmplID)
endif
endif
EmplRef.Close
EmplRef.DelWhere(AddWhere)
endif
endif
Важно помнить, что метод AddWhere не содержит никаких защитных механизмов, происходит добавление новых строк в секцию where SQL-запроса. Поэтому, InputValue надо обеззараживать перед использованием.
В данном влучае опасным символом является двойная кавычка - она нарушит структуру SQL-запроса. Например, если в поле ввода ввести текст Фамилия"Должность. В качестве решения можно заменить строку кода
Replace(InputValue; ' '; '%')
такой строкой:
Replace(Replace(InputValue; ' '; '%'); '"'; '""')
Тут каждая двойная кавычка заменяется на пару двойных кавычек. А при выполнении SQL-запроса каждая пара будет восприниматься как одна двойная кавычка. То есть на результаты SQL-запроса данная замена не повлияет (проверил).
Можно еще оспорить предлагаемую замену, в следующем аспекте: является ли хорошим стилем программирования обеззараживать значение InputValue в момент включения его в SQL-запрос, не лучше ли будет первой строкой кода произвести все замены. Можно сделать и так:
SafeInputValue = Replace(Replace(InputValue; ' '; '%'); '"'; '""')
И ниже использовать уже SafeInputValue.
Авторизуйтесь, чтобы написать комментарий