В процессе разработки конфигураций на платформе 1С:Предприятие 8.3 перед разработчиком часто возникает задача: предоставить пользователю возможность выбора значения в ячейке табличной части не из тяжеловесной стандартной формы выбора справочника, а из компактного динамического выпадающего списка. Источником данных для такого списка может служить колонка предварительно заполненной таблицы значений, массив или результат запроса к базе данных.
В этой статье мы подробно разберем, как правильно реализовать данный функционал на управляемых формах. Мы изучим несколько альтернативных способов решения задачи — от классического асинхронного вызова списка до использования штатного механизма автоподбора платформы — а также выясним, почему иногда выбранное значение не сразу отображается на экране и как это исправить.
Представим сценарий: у нас есть документ, в табличную часть которого необходимо ввести данные. Одно из полей должно заполняться строго ограниченным набором значений, которые мы динамически получаем на сервере (например, из определенной колонки таблицы значений). Мы хотим, чтобы при нажатии кнопки выбора или при начале редактирования ячейки под ней появлялось удобное меню с возможными вариантами выбора.
Попытка решить эту задачу «в лоб» через простое переопределение параметра ДанныеВыбора в событии НачалоВыбора не всегда приводит к успеху у начинающих разработчиков. Часто возникает ситуация, когда список на экране появляется, но после клика по нужному пункту ячейка визуально остается пустой, а новое значение отображается только после перехода на другую строку ТЧ. Давайте разберем по шагам, почему так происходит, и реализуем надежные механизмы работы интерфейса.
Этот подход является универсальным и позволяет полностью контролировать процесс выбора элемента пользователем. Мы перехватываем стандартное событие начала выбора ячейки, отменяем его, формируем собственный список значений и асинхронно показываем его пользователю.
Для реализации этого способа нам понадобятся три составляющие: клиентский обработчик события начала выбора, серверная функция для подготовки массива данных и процедура обратного вызова (оповещение), которая сработает после того, как пользователь кликнет по элементу списка.
Давайте подробно рассмотрим программный код, который решает эту задачу:
&НаКлиенте
Процедура ТоварыНоменклатураНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Шаг 1. Отменяем стандартное открытие формы выбора справочника
СтандартнаяОбработка = Ложь;
// Шаг 2. Получаем массив значений с сервера (например, результат запроса или выгрузка из ТЗ)
МассивДанных = ПолучитьМассивДляВыбораНаСервере();
// Шаг 3. Инициализируем СписокЗначений и заполняем его полученным массивом
СписокВыбора = Новый СписокЗначений();
СписокВыбора.ЗагрузитьЗначения(МассивДанных);
// Шаг 4. Создаем описание оповещения, указывая процедуру-обработчик на клиенте
Оповещение = Новый ОписаниеОповещения("ПослеВыбораИзСписка", ЭтаФорма);
// Шаг 5. Показываем всплывающее меню выбора под активным элементом формы
ЭтаФорма.ПоказатьВыборИзСписка(Оповещение, СписокВыбора, Элемент);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораИзСписка(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
// Если пользователь закрыл список или нажал Esc, ничего не делаем
Если ВыбранныйЭлемент = Неопределено Тогда
Возврат;
КонецЕсли;
// Шаг 6. Записываем выбранное значение в текущую строку табличной части
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
ТекущиеДанные.Номенклатура = ВыбранныйЭлемент.Значение;
КонецЕсли;
// Решение проблемы "зависания" отображения: принудительно завершаем редактирование ячейки
Элементы.Товары.ЗакончитьРедактированиеСтроки(Ложь);
КонецПроцедуры
&НаСервере
Функция ПолучитьМассивДляВыбораНаСервере()
// В реальной задаче здесь может быть выгрузка колонки из Таблицы Значений.
// Для примера сформируем массив первых 10 элементов справочника Номенклатура.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Возврат РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
Иначе
Возврат Новый Массив;
КонецЕсли;
КонецФункции
Важное примечание по решению проблемы обновления экрана: Когда пользователь выбирает элемент из списка, ячейка табличной части на клиенте все еще находится в фокусе и в активном режиме редактирования текста. Платформа ожидает ручного ввода или завершения процесса редактирования. Программное изменение поля через конструкцию ТекущиеДанные.Номенклатура = ВыбранныйЭлемент.Значение; меняет данные в объекте, но не обновляет активное текстовое поле ввода на экране мгновенно.
Для того чтобы визуально применить изменения в ту же секунду, мы используем метод таблицы управляемой формы Элементы.Товары.ЗакончитьРедактированиеСтроки(Ложь). Параметр Ложь указывает платформе, что редактирование завершено успешно и внесенные изменения не нужно отменять. Это мгновенно перерисовывает ячейку с новым значением.
Существует более простой, элегантный и современный способ, который не требует написания асинхронных процедур оповещения и ручной записи значений в текущую строку табличной части. Платформа 1С умеет автоматически обрабатывать заполнение переменной ДанныеВыбора прямо в событии НачалоВыбора.
Если мы передадим заполненный список значений в этот параметр и установим СтандартнаяОбработка = Ложь, платформа сама визуализирует выпадающее меню под ячейкой, перехватит клик пользователя, запишет выбранное значение в связанный реквизит строки и корректно завершит редактирование ячейки с обновлением экрана.
Давайте проанализируем этот изящный код:
&НаКлиенте
Процедура ТоварыНоменклатураНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Отключаем стандартную форму выбора
СтандартнаяОбработка = Ложь;
// Формируем список выбора
МассивДанных = ПолучитьМассивДляВыбораНаСервере();
СписокВыбора = Новый СписокЗначений();
СписокВыбора.ЗагрузитьЗначения(МассивДанных);
// Передаем список напрямую в платформенный параметр ДанныеВыбора
ДанныеВыбора = СписокВыбора;
// Платформа выполнит все остальные действия автоматически!
КонецПроцедуры
Критически важное правило: Для корректной работы этого механизма типы значений в вашем списке выбора должны строго совпадать с типом реквизита табличной части, к которому привязана колонка. Если колонка имеет тип СправочникСсылка.Номенклатура, то элементы списка выбора должны содержать ссылки на элементы справочника. Если колонка текстовая (тип Строка), то в список нужно добавлять исключительно строковые значения.
Если список возможных значений ячейки невелик и относительно стабилен, мы можем перевести элемент формы в режим классического выпадающего списка (Combobox). В этом случае пользователю не придется нажимать на кнопку с троеточием — поле сразу превратится в поле выбора со стрелочкой «вниз».
Разберем по шагам настройку этого режима:
Да.Истина.СписокВыбора данного элемента формы.Программное наполнение списка выбора в таком режиме выглядит следующим образом:
&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Очищаем старые значения списка выбора для элемента
Элементы.ТоварыНоменклатура.СписокВыбора.Очистить();
// Получаем актуальный список значений
МассивДанных = ПолучитьМассивДляТекущейСтроки(ТекущиеДанные);
// Заполняем локальный список выбора элемента формы
Элементы.ТоварыНоменклатура.СписокВыбора.ЗагрузитьЗначения(МассивДанных);
КонецЕсли;
КонецПроцедуры
Этот способ максимально удобен для пользователя, так как поле ведет себя как стандартный веб-список выбора, исключая лишние клики по экрану и гарантируя мгновенную запись данных.
Мы подробно проанализировали три различных способа реализации динамического выпадающего списка в ячейке табличной части 1С 8.3 на управляемых формах. Каждый метод хорош для своих задач: использование параметра ДанныеВыбора отлично подходит для простых сценариев подмены стандартного выбора, асинхронный вызов ПоказатьВыборИзСписка незаменим при реализации сложной логики обработки выбранных данных, а включение режима выбора из списка (Combobox) обеспечивает максимальную эргономику интерфейса. Применяйте эти решения в своих проектах для создания удобного и отзывчивого интерфейса!