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

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

В разработке на платформе 1С часто возникает задача: при выборе значения в одном поле формы необходимо автоматически заполнить другое. Например, при выборе контрагента подставить его основной договор, или, как в нашем случае, при выборе предмета задачи установить периодичность ее выполнения. Давайте разберем, как правильно реализовать такой механизм в управляемых формах, какие события использовать и почему стандартный подход "в лоб" не всегда работает.

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

Решение 1: Использование события `ПриИзменении` для динамического заполнения

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

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

Посмотрим на пример реализации. Сначала создадим клиентский обработчик события.

В модуле формы это будет выглядеть так:


&НаКлиенте
Процедура ПредметВзаимодействияПриИзменении(Элемент)
    // Вызываем серверную процедуру для установки значения
    УстановитьПериодичностьНаСервере();
КонецПроцедуры

Почему мы вызываем сервер? Хотя значение ПредметВзаимодействия доступно на клиенте, изменять основной реквизит объекта (Объект.Периодичность) следует на сервере, чтобы обеспечить целостность данных и выполнение всех серверных проверок. Разделение логики на клиентскую и серверную — это хорошая практика в 1С.

Теперь напишем саму серверную процедуру. Директива &НаСервереБезКонтекста используется, когда процедуре не нужен полный контекст формы, что немного оптимизирует вызов. Если же вам нужны данные формы (не только реквизиты объекта), используйте &НаСервере.


&НаСервереБезКонтекста
Процедура УстановитьПериодичностьНаСервере()
    // Здесь должна быть ваша логика.
    // Например, мы можем проверить, что предмет является ссылкой на определенный справочник,
    // и установить значение по умолчанию.
    
    // В простом примере, как в обсуждении на форуме, можно просто присвоить значение.
    // В реальной задаче здесь будет анализ значения Объект.ПредметВзаимодействия.
    Объект.Периодичность = Перечисления.Периодичность.РазВГод; 
    
    // Если логика сложнее, она может выглядеть так:
    // Если ТипЗнч(Объект.ПредметВзаимодействия) = Тип("СправочникСсылка.Проекты") Тогда
    //     Объект.Периодичность = Объект.ПредметВзаимодействия.ОсновнаяПериодичностьЗадач;
    // Иначе
    //     Объект.Периодичность = ПредопределенноеЗначение("Перечисление.Периодичность.ПустаяСсылка");
    // КонецЕсли;
КонецПроцедуры

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

Решение 2: Заполнение данных при открытии существующего элемента

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

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


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // Проверяем, если периодичность еще не заполнена
    Если ТекущийОбъект.Периодичность = Перечисления.Периодичность.ПустаяСсылка Тогда
        // и при этом предмет взаимодействия уже есть,
        Если ЗначениеЗаполнено(ТекущийОбъект.ПредметВзаимодействия) Тогда
            // то выполняем логику заполнения
            // (логика может быть вынесена в отдельную общую процедуру)
            УстановитьПериодичностьПоПредмету(ТекущийОбъект);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Процедура УстановитьПериодичностьПоПредмету(ОбъектЗадачи)
    // Здесь ваша логика, аналогичная той, что в процедуре УстановитьПериодичностьНаСервере()
    // ...
    ОбъектЗадачи.Периодичность = Перечисления.Периодичность.РазВГод;
КонецПроцедуры

Важный момент: Код в ПриЧтенииНаСервере изменяет данные реквизитов формы (Объект), но не записывает их в базу данных. Изменения будут сохранены только тогда, когда пользователь нажмет кнопку "Записать" или "Провести".

Дополнительный сценарий: передача начальных значений при открытии формы

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

Для этого используется механизм параметров формы. При вызове метода ОткрытьФорму() мы можем передать структуру с начальными значениями.

Шаг 1. Код вызова формы:

Предположим, у нас есть кнопка на форме документа "Заказ клиента", которая создает новую задачу.


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

Шаг 2. Код приема параметров в форме задачи:

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


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

Таким образом, мы добиваемся того, что при программном создании задачи форма открывается с уже предзаполненным предметом и корректной периодичностью, что значительно упрощает работу пользователя.

Итоги: выбираем правильное событие

Давайте подведем итог и систематизируем, какое событие для чего использовать:

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

← На главную