Как получить значения табличной части справочника для выпадающего списка в документе?

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

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

Разберем типичные ошибки при выборке данных из табличных частей с помощью запросов и пошагово реализуем правильное заполнение списка выбора на управляемой форме.

Анализ ошибки: почему возникает «Колонка не принадлежит коллекции»

Рассмотрим распространенную ошибку при попытке получить данные табличной части через запрос к шапке справочника:


// Ошибочный запрос с вложенной таблицей
Запрос.Текст = "ВЫБРАТЬ
               |    Сотрудники.Склады.(
               |        Ссылка
               |    )
               |ИЗ
               |    Справочник.Сотрудники КАК Сотрудники
               |ГДЕ
               |    Сотрудники.Наименование = &Наименование";

При таком подходе и последующем выполнении кода Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка") платформа генерирует исключение. Выясним причину этой ошибки:

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

Правильное построение запроса к табличной части

Для выборки данных из табличной части справочника необходимо обращаться напрямую к таблице табличной части — Справочник.Сотрудники.Склады. Проанализируем корректную серверную функцию:


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

Обратим внимание на ключевые особенности этого запроса:

  1. Мы обращаемся к физической таблице Справочник.Сотрудники.Склады.
  2. В условии ГДЕ поле Ссылка означает ссылку на владельца строки (нашего сотрудника).
  3. В секции ВЫБРАТЬ мы выбираем именно реквизит табличной части Склад.
  4. Ключевое слово РАЗЛИЧНЫЕ защищает выпадающий список от дублей, если склад был добавлен сотруднику повторно.

Реализация выпадающего списка на управляемой форме

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

Шаг 1. Настройка свойств элемента формы

В свойствах поля ввода Склад на форме документа установим:

  1. КнопкаВыпадающегоСписка = Истина (чтобы у поля появилась стрелка для раскрытия списка).
  2. РежимВыбораИзСписка = Истина (если необходимо запретить выбор складов, не входящих в разрешенный список).

Шаг 2. Заполнение списка выбора перед раскрытием

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


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

Шаг 3. Обработка изменения ответственного

Если пользователь меняет сотрудника в документе, необходимо проверить, подходит ли уже выбранный склад новому сотруднику, и при необходимости очистить поле. Реализуем это в событии ОтветственныйПриИзменении:


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

Альтернативный вариант: открытие стандартной формы выбора с отбором

Если у сотрудников закреплено большое количество складов, выпадающий список может стать неудобным для навигации. В этом случае эффективнее настроить отбор в стандартной форме выбора справочника через событие НачалоВыбора:


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

Такой способ открывает полноценную форму справочника, но пользователь увидит в ней исключительно те позиции, которые переданы в фиксированном массиве отбора.

← На главную