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