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

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

В процессе разработки конфигурации на платформе 1С:Предприятие 8.3 часто возникает задача автоматизации ввода данных. Рассмотрим классическую ситуацию: при выборе определенной категории билета (например, "Входной билет") в табличной части документа поле "Экскурсовод" должно заполняться автоматически значением "Без экскурсовода". Проанализируем, как правильно реализовать эту логику, учитывая особенности управляемых форм и клиент-серверной архитектуры.

Использование события ПриИзменении

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

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

Проблема обращения через «точку» на клиенте

Важно помнить, что на клиенте данные ссылочных типов (таких как СправочникСсылка) доступны ограниченно. Если мы попытаемся написать ТекущаяСтрока.КатегорияБилета.ТипБилета в клиентской процедуре, 1С не сможет напрямую получить значение реквизита ТипБилета из справочника, так как для этого требуется обращение к базе данных на сервере.

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

Реализация с использованием предопределенных значений

Для корректной работы нам понадобится использовать функцию ПредопределенноеЗначение(). Это универсальный способ обращения к значениям перечислений или предопределенным элементам справочников, который работает и на клиенте, и на сервере.

Рассмотрим пример кода, который решает поставленную задачу:


&НаКлиенте
Процедура СоставКатегорияБилетаПриИзменении(Элемент)

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

    // Вызываем серверную функцию для получения свойств категории
    ДанныеКатегории = ПолучитьДанныеКатегорииНаСервере(ТекущаяСтрока.КатегорияБилета);
    
    // Проверяем тип билета
    Если ДанныеКатегории.ТипБилета = ПредопределенноеЗначение("Перечисление.тит_Типбилета.ВходнойБилет") Тогда
        
        // Устанавливаем значение "Без экскурсовода"
        // Рекомендуется сделать этот элемент предопределенным в справочнике "Экскурсоводы"
        ТекущаяСтрока.Экскурсовод = ПредопределенноеЗначение("Справочник.тит_Экскурсоводы.БезЭкскурсовода");
        
    КонецЕсли;

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДанныеКатегорииНаСервере(СсылкаНаКатегорию)
    
    Результат = Новый Структура("ТипБилета, Цена", Неопределено, 0);
    
    Если ЗначениеЗаполнено(СсылкаНаКатегорию) Тогда
        Результат.ТипБилета = СсылкаНаКатегорию.ТипБилета;
        Результат.Цена = СсылкаНаКатегорию.Цена;
    КонецЕсли;
    
    Возврат Результат;

КонецФункции

Почему лучше использовать Структуру и серверный вызов?

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

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

Использование пустой ссылки или предопределенного элемента

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

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

Улучшение пользовательского интерфейса (UI)

Хорошим тоном считается не только заполнять данные, но и подсказывать пользователю, что поле "Экскурсовод" больше не нужно редактировать. Разберем, как заблокировать поле для редактирования, если выбран входной билет.

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

Проверка данных перед записью

Посмотрим на ситуацию шире. Даже если на форме все отрабатывает корректно, данные могут попасть в документ программно (например, через загрузку из Excel). Чтобы обеспечить чистоту данных, рекомендуется продублировать проверку в модуле объекта в процедуре ПередЗаписью или ОбработкаПроверкиЗаполнения.


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    Для Каждого СтрокаТЧ Из Состав Цикл
        Если СтрокаТЧ.КатегорияБилета.ТипБилета = Перечисления.тит_Типбилета.Экскурсия 
            И НЕ ЗначениеЗаполнено(СтрокаТЧ.Экскурсовод) Тогда
            
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Для экскурсионного билета необходимо указать экскурсовода!";
            Сообщение.Поле = "Состав[" + Состав.Индекс(СтрокаТЧ) + "].Экскурсовод";
            Сообщение.УстановитьДанные(ЭтотОбъект);
            Сообщение.Сообщить();
            
            Отказ = Истина;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Такой комплексный подход — использование события ПриИзменении на форме для удобства пользователя и валидация в модуле объекта для надежности — является стандартом профессиональной разработки на платформе 1С:Предприятие 8.

← На главную