В процессе разработки в среде 1С:Предприятие 8.3 начинающие специалисты часто сталкиваются с задачей автоматизации ввода данных. Типичный пример: при выборе значения в поле «Пол» (например, «Мужской») программа должна автоматически подставлять соответствующее значение в другое поле, например, «Личные качества» («Мужчина»). Несмотря на кажущуюся простоту, реализация этой логики в управляемом приложении имеет свои нюансы, связанные с разделением кода на клиентскую и серверную части.
В этой статье мы подробно разберем, почему возникают ошибки при написании кода в лоб, проанализируем архитектуру управляемых форм и найдем оптимальное решение задачи.
Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке написать простой обработчик события система выдает серию ошибок: Переменная не определена (Пол) и Переменная не определена (Перечисления). Выясним причину такого поведения платформы.
Проанализируем контекст выполнения кода. В управляемом приложении код формы чаще всего выполняется на Тонком клиенте (директива &НаКлиенте). На стороне клиента действуют строгие ограничения:
Перечисления доступен только на сервере. Клиент «не знает» о существовании всей структуры перечислений в базе данных.Объект.Таким образом, обращение просто по имени реквизита Пол или попытка вызвать Перечисления.Пол.Мужской напрямую приведет к ошибке компиляции модуля.
Для того чтобы получить ссылку на значение перечисления, не обращаясь к серверу, в 1С существует специальная функция ПредопределенноеЗначение(). Она принимает на вход строковое имя объекта метаданных и возвращает ссылку на него. Это позволяет нам оставить логику на клиенте, что обеспечит максимальную скорость работы интерфейса.
Разберем по шагам правильный алгоритм действий:
Пол и в панели свойств создадим событие ПриИзменении.Объект.Посмотрим на пример готового кода:
&НаКлиенте
Процедура ПолПриИзменении(Элемент)
// Проверяем выбранное значение в реквизите Объект.Пол
Если Объект.Пол = ПредопределенноеЗначение("Перечисление.Пол.Мужской") Тогда
// Устанавливаем зависимое значение
Объект.ЛичныеКачества = ПредопределенноеЗначение("Перечисление.ЛичныеКачества.Мужчина");
ИначеЕсли Объект.Пол = ПредопределенноеЗначение("Перечисление.Пол.Женский") Тогда
Объект.ЛичныеКачества = ПредопределенноеЗначение("Перечисление.ЛичныеКачества.Женщина");
КонецЕсли;
КонецПроцедуры
В данном примере мы используем Объект.Пол, так как Объект — это основной реквизит формы, содержащий данные нашего справочника. Использование ПредопределенноеЗначение позволяет нам избежать лишних серверных вызовов.
Иногда логика сопоставления может быть сложной: например, если нужно не просто подставить значение, а проверить остатки на складах или права доступа пользователя. В этом случае нам не обойтись без серверного контекста. На сервере мы можем использовать привычное обращение к коллекции Перечисления.
Рассмотрим вариант реализации с вызовом серверной процедуры:
&НаКлиенте
Процедура ПолПриИзменении(Элемент)
УстановитьЛичныеКачестваНаСервере();
КонецПроцедуры
&НаСервере
Процедура УстановитьЛичныеКачестваНаСервере()
// На сервере мы можем обращаться к Объект.Пол напрямую,
// а также использовать глобальный контекст Перечисления
Если Объект.Пол = Перечисления.Пол.Мужской Тогда
Объект.ЛичныеКачества = Перечисления.ЛичныеКачества.Мужчина;
ИначеЕсли Объект.Пол = Перечисления.Пол.Женский Тогда
Объект.ЛичныеКачества = Перечисления.ЛичныеКачества.Женщина;
КонецЕсли;
КонецПроцедуры
Важный момент: Использование директивы &НаСервере заставляет систему передавать все данные формы (весь контекст) на сервер и обратно. Если форма «тяжелая», это может вызвать задержки в работе интерфейса.
Проанализируем ситуацию: что произойдет, если пользователь случайно выбрал пол, а затем очистил поле? В приведенных выше примерах старое значение в поле «Личные качества» сохранится, что может привести к логическим ошибкам в базе данных.
Хорошим тоном в программировании 1С считается добавление блока очистки. Рассмотрим, как это выглядит:
&НаКлиенте
Процедура ПолПриИзменении(Элемент)
Если Объект.Пол = ПредопределенноеЗначение("Перечисление.Пол.Мужской") Тогда
Объект.ЛичныеКачества = ПредопределенноеЗначение("Перечисление.ЛичныеКачества.Мужчина");
ИначеЕсли Объект.Пол = ПредопределенноеЗначение("Перечисление.Пол.Женский") Тогда
Объект.ЛичныеКачества = ПредопределенноеЗначение("Перечисление.ЛичныеКачества.Женщина");
Иначе
// Если поле Пол пустое, очищаем ЛичныеКачества
Объект.ЛичныеКачества = ПредопределенноеЗначение("Перечисление.ЛичныеКачества.ПустаяСсылка");
КонецЕсли;
КонецПроцедуры
Представим, что в вашем перечислении не 2, а 10 или 20 значений. Нагромождение конструкций Если...ИначеЕсли...КонецЕсли делает программный код трудночитаемым и сложным в поддержке. Профессиональные разработчики используют для таких целей коллекции Соответствие или Структура.
Выясним, как это работает. Мы можем один раз создать карту соответствий и затем просто получать нужное значение по ключу. Это значительно сокращает объем кода.
Пример реализации через серверную функцию:
&НаСервереБезКонтекста
Функция ПолучитьЗависимоеКачество(ЗначениеПола)
КартаСоответствий = Новый Соответствие;
КартаСоответствий.Вставить(Перечисления.Пол.Мужской, Перечисления.ЛичныеКачества.Мужчина);
КартаСоответствий.Вставить(Перечисления.Пол.Женский, Перечисления.ЛичныеКачества.Женщина);
Возврат КартаСоответствий.Получить(ЗначениеПола);
КонецФункции
&НаКлиенте
Процедура ПолПриИзменении(Элемент)
Объект.ЛичныеКачества = ПолучитьЗависимоеКачество(Объект.Пол);
КонецПроцедуры
Использование директивы &НаСервереБезКонтекста является наиболее производительным вариантом, так как на сервер передается только одно значение (выбранный пол), а не вся форма целиком.
Для корректной работы сопоставления реквизитов в управляемых формах 1С 8.3 необходимо помнить три ключевых правила:
Объект.Пол).Соблюдение этих простых принципов позволит вам создавать стабильный и быстрый код, избегая классических ошибок начинающих разработчиков.