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