Как настроить выбор из справочников и ввод произвольной строки в табличной части 1С

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

В разработке на платформе 1С:Предприятие 8.3 часто возникает необходимость организовывать гибкий ввод данных в табличную часть документа или обработки. Типичный сценарий — когда в одну и ту же колонку табличной части пользователь должен вносить данные разной природы: выбирать из полного справочника, выбирать из отфильтрованного списка (например, сотрудников конкретного контрагента или контактных лиц) либо вводить произвольное наименование текстовой строкой.

Разберем, с какими сложностями можно столкнуться при реализации такого составного ввода и как правильно настроить программное управление формами выбора и типами данных.

Постановка задачи и возникающие сложности

Рассмотрим конкретную техническую задачу. В табличной части документа присутствует колонка Участники. Тип реквизита объявлен как составной, включающий ссылки на справочники СправочникСсылка.Сотрудники, СправочникСсылка.КонтактныеЛица и базовый тип Строка.

Пользователю предоставляется выбор режима ввода:

  1. Все сотрудники — выбор из полного справочника сотрудников.
  2. Сотрудники клиента — выбор только тех сотрудников, которые закреплены за текущим клиентом.
  3. Контактные лица — выбор из списка контактных лиц данного клиента.
  4. Текст (Строка) — ручной ввод произвольного текста без обращения к справочникам.

При стандартной реализации разработчики сталкиваются со следующими проблемами:

  1. При вызове формы выбора через ОткрытьФорму выбранное значение не переносится в ячейку табличной части.
  2. Перестает работать штатный ввод по строке (автоподбор по первому символу).
  3. Пользователь не может вводить текст вручную, так как платформа продолжает требовать выбор ссылочного объекта из диалога типа данных.

Проанализируем причины этих проблем и рассмотрим пошаговые варианты их решения.

Причина 1: Неправильный вызов формы выбора и возвращение значения

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


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

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

Решение: В качестве третьего параметра функции ОткрытьФорму необходимо обязательно передавать элемент управления Элемент, который выступает в роли владельца формы выбора:


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

При передаче Элемент в качестве владельца платформа автоматически свяжет выбранный элемент справочника с ячейкой табличной части и запишет значение при закрытии формы выбора.

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


&НаКлиенте
Процедура УчастникиНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораИзФормы", ЭтотОбъект);
    ПараметрыФормы = Новый Структура;
    
    ОткрытьФорму("Справочник.Сотрудники.ФормаВыбора", ПараметрыФормы, Элемент, , , , ОписаниеОповещения);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораИзФормы(РезультатВыбора, ДополнительныеПараметры) Экспорт
    Если ЗначениеЗаполнено(РезультатВыбора) Тогда
        ТекущаяСтрока = Элементы.ТаблицаУчастники.ТекущиеДанные;
        Если ТекущаяСтрока <> Неопределено Тогда
            ТекущаяСтрока.Участник = РезультатВыбора;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Причина 2: Управление типом и видимостью кнопки выбора

Когда реквизит имеет составной тип, платформа по умолчанию отображает кнопку диалога выбора типа ([Т]) и кнопку выбора из справочника. Если пользователь выбирает режим ввода произвольного текста, необходимо запретить платформе вызывать диалог типов и скрыть кнопку выбора, дав возможность вводить текст напрямую в ячейку.

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

  1. Изменение свойства элемента формы ОграничениеТипа.
  2. Управление свойством элемента КнопкаВыбора.

Разберем, как менять состав доступных типов данных динамически на клиенте:


// Включение режима ввода строки:
Элементы.ТаблицаУчастникиУчастник.ОграничениеТипа = Новый ОписаниеТипов("Строка");
Элементы.ТаблицаУчастникиУчастник.КнопкаВыбора = Ложь;

// Включение режима выбора сотрудника:
Элементы.ТаблицаУчастникиУчастник.ОграничениеТипа = Новый ОписаниеТипов("СправочникСсылка.Сотрудники");
Элементы.ТаблицаУчастникиУчастник.КнопкаВыбора = Истина;

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


ТекущаяСтрока = Элементы.ТаблицаУчастники.ТекущиеДанные;
НовыйТип = Новый ОписаниеТипов("Строка");

Элементы.ТаблицаУчастникиУчастник.ОграничениеТипа = НовыйТип;
ТекущаяСтрока.Участник = НовыйТип.ПривестиЗначение(ТекущаяСтрока.Участник);

Причина 3: Передача отборов в форму выбора без написания сложных запросов

Часто разработчики пытаются сформировать небольшой список (5–6 человек) запросом на сервере и вручную передать его в ДанныеВыбора. Однако платформенные механизмы позволяют наложить фильтр прямо на стандартную форму выбора с помощью структуры Отбор, что требует существенно меньше кода и работает штатно.

Посмотрим на пример передачи фильтра по контрагенту или массиву сотрудников:


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

Поддержка ввода по строке (Автоподбор)

Когда вы переопределяете НачалоВыбора и устанавливаете СтандартнаяОбработка = Ложь, ввод по строке может перестать работать. Чтобы вернуть быструю подстановку элементов при вводе текста с клавиатуры, используем событие элемента формы ОбработкаАвтоПодбора:


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

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

Пошаговый алгоритм правильной реализации

Выстроив понятную архитектуру, объединим все рекомендации в единую рабочую схему:

  1. Добавляем в табличную часть辅助 реквизит ВидУчастника (например, типа ПеречислениеСсылка.ВидыУчастников со значениями: ВсеСотрудники, СотрудникиКлиента, КонтактныеЛица, Текст).
  2. В обработчике ПриИзменении колонки ВидУчастника настраиваем доступность ввода и ограничиваем допустимые типы.
  3. В событии ПриАктивизацииСтроки табличной части обновляем свойства элемента управления под текущую выделенную строку.
  4. В событии НачалоВыбора проверяем выбранный вид и открываем форму с нужными отборами.

Проанализируем итоговый программный код управляемой формы:


&НаКлиенте
Процедура ТаблицаУчастникиВидУчастникаПриИзменении(Элемент)
    ОбновитьОграничениеТипаИВидимость();
КонецПроцедуры

&НаКлиенте
Процедура ТаблицаУчастникиПриАктивизацииСтроки(Элемент)
    ОбновитьОграничениеТипаИВидимость();
КонецПроцедуры

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

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

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

← На главную