В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача динамического изменения интерфейса формы в зависимости от данных, которые выбирает пользователь. Типичный пример: в документе ПриходныйОрдер необходимо скрывать или показывать колонку НаценкаВРознице в зависимости от того, какой ВидСклада указан у выбранного в документе склада. Если склад оптовый — колонка не нужна, если розничный — она должна появиться.
Разберем подробно, как реализовать эту логику, учитывая особенности клиент-серверной архитектуры управляемых форм.
Проанализируем типичную ошибку начинающих разработчиков. Попытка написать на клиенте код вида Если Объект.Склад.ВидСклада = ... приведет к ошибке или не даст результата. Это происходит потому, что на клиенте объект Склад является лишь ссылкой (уникальным идентификатором). Все остальные данные (реквизиты справочника) хранятся в базе данных на сервере.
Чтобы получить значение реквизита ВидСклада, нам необходимо либо выполнить контекстный серверный вызов, либо воспользоваться специальными функциями, которые платформа или библиотека стандартных подсистем (БСП) предоставляют для получения данных по ссылке.
Если ваша конфигурация построена на базе современных типовых решений (УТ 11, ERP, Бухгалтерия 3.0), в ней наверняка присутствует общий модуль ОбщегоНазначения. Рассмотрим наиболее эффективный способ получения значения реквизита с его помощью.
Процедура обработки изменения склада на форме будет выглядеть следующим образом:
&НаКлиенте
Процедура СкладПриИзменении(Элемент)
// Получаем вид склада через серверную функцию БСП
ВидСклада = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Объект.Склад, "ВидСклада");
// Определяем условие видимости
// Предположим, ВидСклада — это перечисление
ЭтоОптовый = (ВидСклада = ПредопределенноеЗначение("Перечисление.ВидыСклада.Оптовый"));
// Управляем видимостью колонки
// Если склад оптовый, видимость колонки НаценкаВРознице устанавливаем в Ложь
Элементы.ТоварыНаценкаВРознице.Видимость = НЕ ЭтоОптовый;
КонецПроцедуры
Обратите внимание на использование ПредопределенноеЗначение. Эта функция позволяет на клиенте получить ссылку на элемент перечисления или предопределенный элемент справочника без обращения к серверу вручную.
Если вы работаете в самописной конфигурации, где нет модуля ОбщегоНазначения, или вам нужно получить сразу несколько реквизитов (например, и вид склада, и признак материальной ответственности), целесообразно написать свою серверную функцию. Рассмотрим, как это сделать правильно, чтобы минимизировать нагрузку на систему.
Выясним причину, по которой лучше использовать запрос, а не обращение к объекту. Обращение к объекту через Ссылка.ПолучитьОбъект() считывает из базы абсолютно все поля, что избыточно. Запрос же выбирает только нужные нам данные.
&НаСервереБезКонтекста
Функция ПолучитьВидСклада(СсылкаНаСклад)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Склады.ВидСклада КАК ВидСклада
|ИЗ
| Справочник.Склады КАК Склады
|ГДЕ
| Склады.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаСклад);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.ВидСклада;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Теперь эту функцию можно вызвать в обработчике события ПриИзменении на клиенте. Использование &НаСервереБезКонтекста критически важно для производительности, так как при таком вызове на сервер не передаются данные всей формы документа.
Проанализируем ситуацию: если мы напишем код только в событии СкладПриИзменении, то при открытии уже созданного документа колонка всегда будет видима (или невидима по умолчанию), пока пользователь вручную не перевыберет склад. Чтобы интерфейс соответствовал данным сразу при открытии, необходимо продублировать логику.
Рассмотрим обязательные места установки видимости:
Лучшим решением будет вынести логику установки видимости в отдельную процедуру:
&НаСервере
Процедура УстановитьВидимостьКолонокНаСервере()
// На сервере мы можем обращаться к реквизитам через точку
Если ЗначениеЗаполнено(Объект.Склад) Тогда
ВидСклада = Объект.Склад.ВидСклада;
ЭтоОптовый = (ВидСклада = Перечисления.ВидыСклада.Оптовый);
Элементы.ТоварыНаценкаВРознице.Видимость = НЕ ЭтоОптовый;
КонецЕсли;
КонецПроцедуры
Посмотрим на задачу под другим углом. В 1С есть мощный механизм Условного оформления. Обычно его используют для раскраски строк, но он также умеет управлять видимостью. Плюс этого метода в том, что он работает декларативно и часто не требует написания кода в каждом событии.
Разберем по шагам настройку через код в ПриСозданииНаСервере:
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Что оформляем (какую колонку скрываем)
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТоварыНаценкаВРознице");
// 2. Условие (когда скрываем)
// Внимание: для этого метода реквизит Склад.ВидСклада должен быть
// доступен в данных формы (например, добавлен в скрытый реквизит)
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Склад.ВидСклада");
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.ПравоеЗначение = Перечисления.ВидыСклада.Оптовый;
// 3. Результат (устанавливаем видимость в Ложь)
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Видимость", Ложь);
Однако стоит помнить, что программное управление свойством Видимость через Элементы более надежно, если логика скрытия зависит от прав доступа или сложных бизнес-процессов.
Проанализируем разницу между Видимость и ПользовательскаяВидимость.
Если вы программно устанавливаете Видимость = Ложь, колонка полностью исключается из состава формы для текущего сеанса. Пользователь не сможет включить её через меню "Изменить форму". Если же ваша задача просто "спрятать" её по умолчанию, но оставить возможность включения продвинутым пользователям, используйте ПользовательскаяВидимость.
Также не забывайте про Связи параметров выбора. Если в документе выбран "Оптовый" склад, и это влияет на доступность товаров в табличной части, возможно, стоит ограничить сам выбор складов, чтобы пользователь не мог выбрать неподходящий тип склада для данного вида документа. Это настраивается в свойствах реквизита в Конфигураторе.
Таким образом, мы выяснили, что для управления видимостью колонки в зависимости от реквизита справочника необходимо обеспечить получение этого реквизита с сервера (через функции БСП или собственные запросы) и установить соответствующие значения свойств элементов формы в ключевых событиях жизненного цикла формы.