Как в реквизит формы передать список номенклатуры из таблицы в 1С?

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

При разработке интерфейсов в среде «1С:Предприятие» часто возникает задача динамического ограничения выбора пользователя. Типичный сценарий: при открытии подчиненной формы (например, для ввода параметров или записи в регистр сведений) необходимо предоставить пользователю возможность выбирать номенклатуру только из тех позиций, которые уже присутствуют в табличной части исходного документа. В этой статье мы подробно разберем, как решить эту задачу в обычных формах, проанализируем частые синтаксические ошибки начинающих разработчиков и рассмотрим альтернативные, более гибкие архитектурные подходы.

Постановка задачи и разбор базового алгоритма

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

Для реализации этого механизма необходимо пройти три основных этапа:

  1. Получить доступ к табличной части документа-владельца.
  2. Выгрузить колонку Номенклатура в массив.
  3. Загрузить этот массив в список выбора элемента управления на форме.

Шаг 1. Исправление типичных синтаксических ошибок обращения к контексту

При переходе от управляемых форм (УФ) к обычным формам (ОФ) разработчики часто путают синтаксис работы с элементами и контекстом формы. Выясним причину популярных ошибок на конкретных примерах.

В управляемых формах обращение к элементам происходит через коллекцию Элементы, а в обычных формах используется коллекция ЭлементыФормы. Попытка использовать свойство Элементы в обычном приложении вызовет ошибку обращения к необъектным данным.

Еще одна распространенная ошибка — составление избыточных цепочек обращения к объекту-владельцу, таких как:

ЭтаФорма.ВладелецФормы.ДокументОбъект.ЭтотОбъект.ЭтотОбъект.Ссылка...

Такой синтаксис не просто перегружен, но и ошибочен. В обычных формах, если подчиненная форма открывается из формы документа, свойство ВладелецФормы (или параметр ЭтаФорма.ВладелецФормы) возвращает саму форму документа. Чтобы обратиться к данным документа-владельца напрямую, достаточно использовать свойство ДокументОбъект у этой формы.

Также важно помнить правила обращения к свойствам объекта через квадратные скобки. Если имя табличной части передается как строковый литерал (например, при динамическом обращении), его обязательно нужно брать в кавычки. Сравним неправильный и правильный варианты:

Ошибочно:


// Платформа выдаст ошибку "Переменная не определена (Товары)"
ВладелецФормы.ДокументОбъект[Товары] 

Правильно:


ВладелецФормы.ДокументОбъект["Товары"]
// или прямое обращение через точку:
ВладелецФормы.ДокументОбъект.Товары

Шаг 2. Выгрузка колонки и загрузка в список выбора

Для получения массива значений из определенной колонки табличной части используется метод ВыгрузитьКолонку(). Этот метод идеально подходит, так как он возвращает стандартный тип Массив, который легко передается в метод ЗагрузитьЗначения() списка выбора элемента формы.

Рассмотрим рабочий код, который необходимо разместить в обработчике формы (например, в процедуре ПриОткрытии подчиненной формы):


Процедура ПриОткрытии()
    
    // Проверяем, что владелец формы задан корректно
    Если ВладелецФормы <> Неопределено Тогда
        
        Попытка
            // Получаем массив номенклатуры из табличной части "Товары" документа-владельца
            МассивНоменклатуры = ВладелецФормы.ДокументОбъект.Товары.ВыгрузитьКолонку("Номенклатура");
            
            // Очищаем и загружаем новые значения в список выбора элемента формы
            ЭлементыФормы.Номенклатура.СписокВыбора.ЗагрузитьЗначения(МассивНоменклатуры);
        Исключение
            Предупреждение("Не удалось загрузить список номенклатуры из документа-владельца!");
        КонецПопытки;
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 3. Важные свойства элемента формы (Интерфейсная часть)

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

Проанализируем ключевые свойства элемента управления поля ввода в Конструкторе формы:


Архитектурно правильное решение: Устранение сильной связанности

Разберем важный архитектурный нюанс. Прямое обращение подчиненной формы к свойствам владельца (ВладелецФормы.ДокументОбъект...) создает так называемую сильную связанность (tight coupling) контекстов. Если в будущем структура родительского документа изменится, или вы решите вызвать эту форму из другого места конфигурации, код подчиненной формы сломается.

Правильным решением является передача параметров «сверху вниз». Давайте посмотрим на пример, как организовать передачу данных из формы документа-владельца.

Код в форме документа-источника:


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

В самой открываемой форме нам достаточно объявить экспортную переменную в самом верху модуля формы и обработать её при открытии:


Перем ПереданныйМассивНоменклатуры Экспорт;

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

Этот способ гораздо более гибкий и безопасный с точки зрения поддержки программного кода.


Альтернативный вариант: Динамический вызов функции «ВыбратьИзСписка»

Рассмотрим еще один интересный юзабилити-прием. Иногда не требуется постоянно хранить список выбора внутри элемента формы. Список можно показывать динамически — прямо в момент клика по полю ввода. Для этого используется встроенная функция глобального контекста ВыбратьИзСписка().

Для реализации этого метода перейдем в свойства поля ввода номенклатуры на форме и создадим обработчик события НачалоВыбора:


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

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

Альтернатива для больших списков: Ограничение формы выбора

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

Посмотрим на пример реализации такого отбора в обработчике НачалоВыбора для обычных форм:


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

Используя этот метод, вы сохраняете для пользователя все удобства стандартного окна выбора (поиск по строке, иерархию папок, сортировку), но при этом жестко ограничиваете доступный перечень товаров рамками текущего документа.

← На главную