При разработке интерфейсов на управляемых формах часто возникает задача ограничить выбор значений в колонке табличной части индивидуальным набором вариантов, зависящим от данных текущей строки. Например, в зависимости от выбранного типа номенклатуры или условий договора список доступных статусов или единиц измерения должен быть разным.
Разберем, почему в управляемом интерфейсе колонка таблицы ведет себя иначе, чем в обычных формах, какое событие формы следует использовать для динамического заполнения списка и как избежать типичных ошибок производительности и отображения данных.
Проанализируем главную сложность: в управляемых формах элемент управления колонки таблицы (поле ввода) создается в единственном экземпляре на всю таблицу. Физически не существует отдельных элементов управления для каждой строки. Поэтому, когда мы изменяем свойство СписокВыбора у колонки, это изменение мгновенно затрагивает элемент управления в целом.
Отсюда вытекают две критически важные проблемы:
ПриАктивизацииСтроки приводит к постоянным вызовам сервера при каждом перемещении курсора по строкам таблицы, что вызывает заметные зависания интерфейса.РежимВыбораИзСписка = Истина, платформа пытается сопоставить текущее значение ячейки со значениями из списка выбора. Если список динамически перезаписан для другой строки, в остальных строках вместо представлений могут отображаться пустые ячейки или сырые идентификаторы.Перед тем как писать программный код, настроим свойства поля таблицы в конфигураторе или через свойства формы:
Истина (или Да). Это обеспечит отображение стрелки выпадающего списка в ячейке.Ложь, если состав списков между строками различается. Это гарантирует корректную отрисовку ранее введенных данных в других строках.Оптимальным событием для обновления списка является НачалоВыбораИзСписка. Оно возникает непосредственно в момент, когда пользователь нажимает на кнопку выпадающего списка в конкретной ячейке, реализуя принцип «ленивой загрузки» данных.
Рассмотрим по шагам реализацию данного обработчика на клиенте и получение данных на сервере:
&НаСервереБезКонтекста
Функция ПолучитьСписокВыбораДляСтроки(ЗначениеУсловия)
Список = Новый СписокЗначений;
// Здесь выполняем запрос к базе данных с учетом переданного условия
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СправочникНоменклатура.Ссылка КАК Значение,
| СправочникНоменклатура.Наименование КАК Представление
|ИЗ
| Справочник.Номенклатура КАК СправочникНоменклатура
|ГДЕ
| СправочникНоменклатура.Родитель = &Родитель";
Запрос.УстановитьПараметр("Родитель", ЗначениеУсловия);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Список.Добавить(Выборка.Значение, Выборка.Представление);
КонецЦикла;
Возврат Список;
КонецФункции
&НаКлиенте
Процедура ТоварыКолонкаЗначениеНачалоВыбораИзСписка(Элемент, СтандартнаяОбработка)
// Получаем текущие данные строки
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Обязательно очищаем предыдущие значения списка,
// чтобы элементы не дублировались при повторном открытии
Элемент.СписокВыбора.Очистить();
// Получаем актуальный список для текущей строки
СписокДанных = ПолучитьСписокВыбораДляСтроки(ТекущаяСтрока.Группа);
// Заполняем список выбора элемента формы
Для Каждого ЭлементСписка Из СписокДанных Цикл
Элемент.СписокВыбора.Добавить(ЭлементСписка.Значение, ЭлементСписка.Представление);
КонецЦикла;
КонецПроцедуры
Важно: вызов Элемент.СписокВыбора.Очистить() строго обязателен. Если его пропустить, при каждом повторном нажатии на кнопку выбора элементы будут дублироваться и список разрастется.
Если требуется полностью изолировать логику выбора от элемента управления и избежать потенциальных проблем с переопределением СписокВыбора для всей таблицы, используем метод ПоказатьВыборИзСписка. Перехватим событие НачалоВыбора, отключим стандартную обработку и покажем модальное выпадающее меню.
Разберем пример реализации:
&НаКлиенте
Процедура ТоварыКолонкаЗначениеНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем список значений с сервера
СписокДляВыбора = ПолучитьСписокВыбораДляСтроки(ТекущаяСтрока.Группа);
// Настраиваем оповещение о завершении выбора
Оповещение = Новый ОписаниеОповещения("ПослеВыбораИзСписка", ЭтотОбъект);
// Показываем меню, привязанное к текущему элементу формы
ПоказатьВыборИзСписка(Оповещение, СписокДляВыбора, Элемент);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораИзСписка(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
Если ВыбранныйЭлемент = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
ТекущаяСтрока.КолонкаЗначение = ВыбранныйЭлемент.Значение;
КонецЕсли;
КонецПроцедуры
Этот способ более безопасен для интерфейса, так как свойство СписокВыбора самого элемента управления остается нетронутым.
Соответствие. Это исключит повторные серверные вызовы при повторном клике.НачалоВыбораИзСписка срабатывает только при клике мышью по кнопке раскрывающегося списка. Если пользователю требуется вводить текст вручную с автоподбором вариантов, дополнительно переопределите обработчики события АвтоПодбор и ОкончаниеВводаТекста у того же поля ввода.