Как динамически связать список выбора единиц измерения с выбранной номенклатурой в табличной части документа 1С:УНФ?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой Управленческий учет
← На главную

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

Рассмотрим ситуацию, когда необходимо связать поле ОперацииЕдиницаИзмерения1 в табличной части документа «Сдельный наряд» с реквизитом Номенклатура таким образом, чтобы список выбора для единицы измерения отображал только единицы, указанные для выбранной номенклатуры. Например, если для конкретной номенклатуры задано две единицы измерения, то именно эти две единицы должны быть доступны для выбора в соответствующей строке табличной части.

Анализ начальной попытки и ее недостатки

Изначально была предпринята попытка программно управлять списком выбора с помощью кода в обработчике события ПриИзменении для колонки Номенклатура:


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

Проанализируем ключевые недостатки этого подхода:

  1. Вызов ПолучитьОбъект на клиенте: Строка Номенклатура = Элемент.ТекущаяСтрока.Номенклатура.ПолучитьОбъект; является неэффективной и нежелательной в клиентском коде. Каждый раз при изменении номенклатуры она вызывает обращение к серверу и загрузку всех данных объекта, что может значительно замедлять работу формы, особенно в табличных частях с большим количеством строк. Для получения данных с сервера всегда следует использовать серверные вызовы.
  2. Изменение СписокВыбора для всей колонки: Строка Элементы.ТабличнаяЧастьНоменклатура.Колонки.ОперацииЕдиницаИзмерения1.СписокВыбора.ЗагрузитьЗначения(СписокЕдиницИзмерения); изменяет свойство СписокВыбора для всей колонки табличной части, а не для конкретной ячейки текущей строки. Это означает, что при выборе номенклатуры в одной строке, список выбора для единицы измерения изменится во всех строках этой колонки, что приведет к некорректному поведению и путанице для пользователя.
  3. Отсутствие серверного взаимодействия: Хотя ПолучитьОбъект и является серверным вызовом по сути, он происходит синхронно на клиенте и не является оптимальным способом получить лишь часть данных. Для формирования списка выбора необходимо выполнять запросы к базе данных, что всегда должно происходить в серверном контексте.

Проверка стандартного функционала 1С:УНФ

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

Рекомендуемый подход: Использование «СвязейПараметровВыбора»

Механизм СвязиПараметровВыбора является наиболее предпочтительным и эффективным способом для реализации зависимых списков выбора в 1С:Предприятии. Он позволяет декларативно, без написания сложного кода, устанавливать фильтры для одного поля выбора на основе значения другого поля, при этом платформа автоматически обрабатывает обновление списка при изменении связанного поля. Это обеспечивает высокую производительность, надежность и простоту поддержки.

Разберем по шагам, как настроить СвязиПараметровВыбора для нашего случая:

  1. Убедимся в наличии механизма хранения единиц измерения для номенклатуры:

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

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

    Важно: убедитесь, что тип данных реквизита ОперацииЕдиницаИзмерения1 в документе «Сдельный наряд» установлен как СправочникСсылка.ЕдиницыИзмерения.

  2. Откроем форму документа «Сдельный наряд» в конфигураторе:

    Находим форму элемента документа, где расположена табличная часть с номенклатурой и единицей измерения.

  3. Найдем элемент управления, соответствующий колонке «ОперацииЕдиницаИзмерения1»:

    В дереве элементов формы развернем табличную часть (например, ТабличнаяЧастьНоменклатура или Операции, в зависимости от имени в вашей конфигурации). Внутри этой табличной части найдем элемент управления, соответствующий колонке ОперацииЕдиницаИзмерения1 (это будет ПолеВвода).

  4. Перейдем на вкладку «СвязиПараметровВыбора» в свойствах этого элемента:

    В палитре свойств для найденного элемента ПолеВвода находим раздел «Связи параметров выбора».

  5. Добавим новую связь:

    Нажимаем кнопку «Добавить» (зеленый плюс) для создания новой связи.

  6. Настроим параметры связи:
    • Параметр: Здесь мы указываем имя параметра отбора, который будет использоваться для фильтрации справочника ЕдиницыИзмерения. В большинстве случаев, если единицы измерения подчинены номенклатуре через реквизит Владелец, то параметр будет Отбор.Владелец. Это стандартный параметр отбора для подчиненных справочников.
    • Поле: Указываем поле в текущей строке табличной части документа, из которого будет браться значение для фильтрации. В нашем случае это реквизит Номенклатура. Мы указываем его как Номенклатура (без префиксов, если реквизит называется именно так в табличной части).
    • Режим: Обычно устанавливаем значение Использование.
    • Источник значения: Здесь указываем, откуда брать значение для параметра. Если связь устанавливается внутри табличной части и значение берется из другой колонки той же строки, то стандартным выбором будет ТекущаяСтрокаДанных.Номенклатура. Это означает, что значение будет браться из реквизита Номенклатура текущей строки данных табличной части.

Пример настройки в свойствах элемента управления (визуально):

  1. Откройте свойства поля ОперацииЕдиницаИзмерения1.

  2. В группе свойств «Выбор» найдите «Связи параметров выбора» и откройте их.

  3. Добавьте новую связь со следующими значениями:

    • Параметр: Отбор.Владелец
    • Поле: Номенклатура
    • Режим: Использование
    • Источник значения: ТекущаяСтрокаДанных.Номенклатура

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

Альтернативный программный подход (менее предпочтительный для данного сценария)

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

Рассмотрим правильный алгоритм программного решения:

  1. Обработчик события ПриИзменении для колонки Номенклатура (Клиент):

    Создаем обработчик события ПриИзменении для поля Номенклатура в табличной части. В этом обработчике мы будем получать значение выбранной номенклатуры и передавать его на сервер.

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

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

  2. Серверная функция для получения списка единиц измерения (Сервер):

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

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

    Как было упомянуто, установка СписокВыбора для конкретной ячейки табличной части программно — это сложная задача, которую обычно избегают в пользу СвязиПараметровВыбора. В управляемых формах нет прямого аналога установки списка выбора для ячейки. Обычно, если мы хотим программно фильтровать список выбора для элемента в табличной части, мы используем механизм ОбработкаВыбора или ОбработкаПолученияДанныхВыбора, где уже на клиенте или с дополнительным серверным вызовом формируем нужный отбор или список. Однако, это значительно усложняет код по сравнению с декларативным подходом.

    Поэтому мы настоятельно рекомендуем использовать СвязиПараметровВыбора для данной задачи.

Ключевые моменты и лучшие практики

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

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

Таким образом, наиболее правильным и эффективным подходом для решения поставленной задачи является использование механизма СвязиПараметровВыбора, настроив его на основе реквизита Номенклатура в табличной части документа «Сдельный наряд».

← На главную