Как реализовать ввод по строке с дополнительным отбором в обычных формах 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При переходе с управляемых форм на обычные (или при поддержке старых конфигураций, таких как Управление торговлей 10.3, Управление производственным предприятием 1.3 или Комплексная автоматизация 1.1) разработчики часто сталкиваются с аппаратными ограничениями старого интерфейса. Одной из таких задач является доработка стандартного ввода по строке. Представим ситуацию: нам необходимо, чтобы при вводе пользователем наименования или кода в поле выбора справочника система предлагала только те элементы, у которых определенный реквизит (например, НеВыводить) имеет значение Ложь.

В управляемом приложении эта задача решается тривиально — через обработчик ОбработкаПолученияДанныхВыбора в модуле менеджера объекта. Однако в обычных формах (в толстом клиенте) данный обработчик платформой не вызывается для интерактивного автоподбора. Нам приходится использовать классические события элементов управления на форме и механизмы типовых конфигураций. В этой статье мы подробно разберем, как решить эту задачу стандартными средствами, как применить это решение в динамических отчетах и списках значений, а также рассмотрим альтернативный глобальный вариант без написания программного кода.

---

Решение 1. Классический вариант через события формы и общий модуль

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

  1. АвтоПодборТекста — срабатывает в процессе набора текста пользователем.
  2. ОкончаниеВводаТекста — срабатывает, когда пользователь закончил ввод (нажал Enter или перевел фокус) и платформа пытается сопоставить текст с конкретным элементом базы данных.

В типовых конфигурациях на обычных формах (УПП, УТ, КА) логика поиска уже инкапсулирована в общем модуле ПроцедурыПоискаПоСтроке. Мы можем использовать его функции, чтобы не писать запросы вручную. Рассмотрим пошаговый алгоритм настройки.

Откроем форму документа или справочника в конфигураторе, выберем нужное поле ввода и в палитре свойств создадим обработчик события ОкончаниеВводаТекста. Напишем в модуле формы следующий код:


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

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

Разберем, как работает эта конструкция. Метод ОкончаниеВводаТекстаВЭлементеУправления принимает на вход параметры элемента, текст для поиска, а также структуру отборов. Он программно выполняет запрос к таблице справочника, накладывая условие подобия по наименованию/коду и строгое равенство по переданным в структуре полям. Если находится один элемент — он подставляется в поле ввода. Если находится несколько — пользователю открывается мини-список для выбора. Если ничего не найдено с учетом нашего фильтра НеВыводить = Ложь, то переменная Значение остается строковой, и мы возвращаем управление стандартному механизму платформы, который штатно сообщает об ошибке ввода.

---

Решение 2. Реализация отбора в типовых отчетах (на Построителе отчета)

Сложнее обстоит дело, когда дополнительный отбор нужно применить в универсальных отчетах или отчетах на базе ПостроителяОтчета. Настройки отборов в них выводятся динамически в табличное поле (например, ТабличноеПолеОтбор). Мы не можем физически зайти в конфигуратор и дважды кликнуть по ячейке ввода значения отбора, чтобы назначить ей событие. Нам потребуется привязать обработчики программно.

Выполним это в модуле формы отчета, например, в процедуре ПриОткрытии или сразу после инициализации структуры настроек построителя:


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

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

Теперь нам необходимо описать сам обработчик ОтборЗначениеОкончаниеВводаТекста в модуле формы отчета. Обратите внимание, что мы должны накладывать отбор только тогда, когда пользователь вводит данные по конкретному справочнику (например, Справочник Номенклатура), а не по всем полям отбора подряд.


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

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

Благодаря этому методу, динамические поля ввода в таблице настроек отчета начнут подчиняться нашему правилу фильтрации при интерактивном вводе по строке.

---

Решение 3. Как обойти проблему в Списках Значений

Когда поле на форме имеет тип СписокЗначений, стандартный автоподбор текста в нем не работает. При попытке ввода платформа обычно сразу открывает модальное окно редактирования списка. Рассмотрим три архитектурных пути решения этой проблемы.

Вариант А. Использование Таблицы Значений вместо Списка Значений

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

Для ячейки этой таблицы мы легко можем настроить события АвтоПодборТекста и ОкончаниеВводаТекста точно так же, как для обычного поля ввода. Перед записью объекта или формированием отчета мы просто программно выгружаем данные из этой таблицы значений в результирующий список.

Вариант Б. Режим выбора из списка

Если справочник небольшой (до нескольких сотен элементов), мы можем полностью отказаться от ввода по строке через базу данных в пользу выбора из заранее подготовленного массива:

  1. Установим у поля ввода свойства КнопкаСпискаВыбора = Истина и РежимВыбораИзСписка = Истина.
  2. При открытии формы программно заполним свойство СписокВыбора этого элемента управления только теми элементами справочника, у которых реквизит НеВыводить равен Ложь.

Пользователь получит быстрый выпадающий список, в котором заведомо отсутствуют нежелательные элементы.

Вариант В. Фильтрация через форму выбора списка

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


ФормаВыбора = Справочники.Номенклатура.ПолучитьФормуВыбора(, Элемент);
ФормаВыбора.Отбор.НеВыводить.Использовать = Истина;
ФормаВыбора.Отбор.НеВыводить.Значение = Ложь;
ФормаВыбора.Открыть();

---

Решение 4. "Максимально средствами платформы" — использование RLS

Если перед нами стоит задача скрыть элементы с признаком НеВыводить = Истина абсолютно во всей системе (в любых документах, отчетах, списках, при вводе по строке и в программных запросах) для определенных групп пользователей, то написание кода в формах — это избыточный и небезопасный путь. Лучшим решением будет использование встроенного механизма платформы RLS (Ограничение доступа на уровне записей).

Рассмотрим, как это реализовать по шагам:

  1. Откроем конфигуратор и перейдем на вкладку Роли. Выберем роль, назначенную обычным пользователям (например, "Пользователь").
  2. Найдем в списке объектов наш справочник и перейдем на вкладку Шаблоны ограничений или сразу выберем право Чтение.
  3. Для права "Чтение" добавим ограничение доступа к данным (ОДД).
  4. В поле текста ограничения запишем простейший SQL-подобный запрос платформы:

ГДЕ НЕ НеВыводить

После обновления конфигурации базы данных платформа 1С на уровне СУБД начнет автоматически отсекать все элементы, у которых флаг НеВыводить установлен в значение Истина.

Преимущества решения RLS:

Недостатки решения RLS:

← На главную