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