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

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

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

Представим, что у нас есть конфигурация 1С с несколькими справочниками:

  1. Номенклатура
  2. НоменклатураОМС
  3. Кабинеты
  4. КабинетыОМС

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

  1. Наименование: Имеет составной тип данных, включающий СправочникСсылка.Номенклатура и СправочникСсылка.НоменклатураОМС.
  2. Кабинет: Также имеет составной тип данных, включающий СправочникСсылка.КабинетыОМС и СправочникСсылка.Кабинеты.

Наша задача состоит в том, чтобы при выборе значения в поле "Наименование" автоматически ограничивался выбор в поле "Кабинет" той же строки:

Анализ первоначальной попытки и возникающих ошибок

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


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

При запуске конфигурации и попытке выбрать справочник в поле "Наименование" мы сталкиваемся с первой ошибкой:

Поле объекта не обнаружено (Наименование)

{Документ.ВыдачаМатериалов.Форма.ФормаДокумента.Форма(5)}: Если Элемент.Наименование.Ссылка.Тип = Тип("Справочник.НоменклатураОМС") Тогда

Разбираем причину первой ошибки

Эта ошибка возникает из-за неверного обращения к значению поля. В обработчике события ПриИзменении для колонки табличной части, параметр Элемент представляет собой сам элемент управления формы (поле ввода), который и изменился. У этого элемента управления нет свойства Наименование. Значение, которое было выбрано в поле, содержится в свойстве Элемент.Значение.

Кроме того, Элемент.Значение уже является ссылкой на справочник (например, СправочникСсылка.НоменклатураОМС), поэтому обращаться к Элемент.Значение.Ссылка.Тип не нужно. Для получения типа значения достаточно использовать функцию ТипЗнч().

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

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


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

Однако, при таком изменении, мы сталкиваемся со второй ошибкой:

Поле объекта не обнаружено (ТекущаяСтрока)

{Документ.ВыдачаМатериалов.Форма.ФормаДокумента.Форма(6)}: Если ТипЗнч(Элемент.ТекущаяСтрока.Наименование)=Тип("СправочникСсылка.НоменклатураОМС")тогда

Разбираем причину второй ошибки

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

Например, если наша табличная часть на форме называется "Выдано", то текущая строка будет доступна через Элементы.Выдано.ТекущиеДанные.

Рекомендуемое решение: Использование события "ПриНачалеВыбора" и свойства "ОграничениеПоТипу"

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

Рассмотрим по шагам, как реализовать это решение:

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

Предположим, что наша табличная часть на форме называется Выдано.

Пример кода для динамического ограничения выбора в событии "ПриНачалеВыбора"

В этом примере мы используем объект ОписаниеТипов для того, чтобы задать допустимые типы для поля выбора. Если мы хотим разрешить выбор только из одного типа, мы передаем этот тип в конструктор ОписаниеТипов. Если же нам нужно сбросить ограничение или установить его на несколько типов (например, вернуть исходное составное ограничение), мы можем передать в ОписаниеТипов массив типов.


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

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

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

Дополнительное соображение: Очистка поля "Кабинет" при изменении "Наименования"

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

Для обеспечения более строгой логики и улучшения удобства пользователя, мы можем добавить код в обработчик ПриИзменении для колонки "Наименование", который будет очищать поле "Кабинет" в текущей строке, если оно перестает соответствовать новому типу "Номенклатуры".

Пример кода для очистки поля "Кабинет" в событии "ПриИзменении" поля "Наименование"


&НаКлиенте
Процедура ВыданоНаименованиеПриИзменении(Элемент)
    // Элемент здесь - это поле ввода для Наименования.
    // Получаем текущие данные строки табличной части "Выдано".
    ТекущиеДанныеСтроки = Элементы.Выдано.ТекущиеДанные;

    // Проверяем, что текущая строка табличной части существует.
    Если ТекущиеДанныеСтроки <> Неопределено Тогда
        // Получаем текущее значение Кабинета в этой строке.
        СсылкаНаКабинет = ТекущиеДанныеСтроки.Кабинет; 

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

Рекомендуем использовать оба обработчика: ВыданоНаименованиеПриИзменении для очистки зависимого поля при изменении основного, и ВыданоКабинетПриНачалеВыбора для динамического ограничения выбора. Это обеспечит надежную и интуитивно понятную работу с документом.

Важные моменты и рекомендации по дальнейшему обучению

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

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

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

← На главную