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

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

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

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

Выясняем причину: почему получить данные формы «напрямую» по ссылке невозможно?

Для того чтобы понять суть проблемы, нам необходимо четко разграничить два понятия: данные базы данных и данные интерфейса (формы). Это классический пример разделения ответственности в архитектуре программного обеспечения (паттерн MVC — Model-View-Controller).

Когда вы оперируете переменной типа СправочникСсылка (например, ссылкой на номенклатуру или контрагента), вы работаете с уникальным идентификатором (GUID) записи в таблице СУБД. Через эту ссылку (или получаемый из нее объект СправочникОбъект) можно прочитать только те данные, которые жестко закреплены за этой таблицей в метаданных конфигурации:

  1. Стандартные реквизиты (Код, Наименование, Родитель, ПометкаУдаления и т.д.).
  2. Дополнительные реквизиты объекта, созданные разработчиком.
  3. Табличные части справочника.

В то же время реквизиты формы (в управляемых формах) или элементы управления (в обычных формах) — это временные программные сущности. Давайте проанализируем их жизненный цикл:

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

Именно поэтому попытка написать код вида СсылкаНаСправочник.ИмяРеквизитаФормы всегда будет приводить к ошибке: у объекта базы данных просто нет такого свойства.

Ниже представлены проверенные методы, которые помогут нам обойти это ограничение и получить заветное значение.

Способ 1. Чтение данных из первоисточника (Рекомендуемый и самый быстрый метод)

Давайте подумаем логически: если при открытии формы элемента поле ввода заполняется каким-то значением, значит, в коде модуля формы (в процедурах ПриСозданииНаСервере или ПриОткрытии) прописан алгоритм его получения. Данные не могут появиться из ниоткуда.

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

Рассмотрим по шагам, как это сделать программно с помощью запроса или менеджера регистра сведений:


// Пример получения значения из периодического регистра сведений "ЦеныНоменклатуры"
// Если на форме отображалась актуальная цена товара по ссылке СсылкаНаНоменклатуру

Функция ПолучитьЦенуИзПервоисточника(СсылкаНаНоменклатуру, АктуальнаяДата) Экспорт
    
    // Подготовим структуру отбора для получения последней записи регистра
    Отбор = Новый Структура;
    Отбор.Вставить("Номенклатура", СсылкаНаНоменклатуру);
    
    // Обратимся к менеджеру регистра сведений для получения последнего среза
    РесурсЗначение = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(АктуальнаяДата, Отбор);
    
    Возврат РесурсЗначение.Цена;
    
КонецФункции

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


// Альтернативный вариант получения значения через запрос к базе данных
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЦеныНоменклатурыСрезПоследних.Цена КАК АктуальнаяЦена
    |ИЗ
    |	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура = &Номенклатура) КАК ЦеныНоменклатурыСрезПоследних";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаОбъект);

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    НужноеЗначение = Выборка.АктуальнаяЦена;
КонецЕсли;

Способ 2. Программное создание формы в памяти (Обходной путь для сложных расчетов)

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

Давайте рассмотрим, как реализовать этот метод для управляемых форм (актуально для платформ 1С 8.2 и 1С 8.3):


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

Для обычных форм (в режиме толстого клиента, который активно использовался в 1С 8.2) программное получение значения выглядит несколько иначе. Мы обращаемся непосредственно к элементам управления формы:


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

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

Способ 3. Перенос бизнес-логики в модуль менеджера (Best Practices)

Для того чтобы в будущем не сталкиваться с необходимостью «выковыривать» данные из интерфейса, мы рекомендуем придерживаться золотого правила разработки 1С: «Модуль формы отвечает только за визуализацию, а вся бизнес-логика должна находиться на сервере в общих модулях или модулях менеджера».

Давайте разберем правильную схему реализации этой логики по шагам:

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

// Размещаем в Модуле менеджера справочника "Контрагенты"
Функция ПолучитьДополнительныйПараметрКонтрагента(СсылкаНаОбъект) Экспорт
    
    // Сюда помещаем всю логику: запросы к регистрам, вычисления, проверки
    РезультатРасчета = "";
    
    Запрос = Новый Запрос;
    // ... здесь пишем текст запроса ...
    
    Возврат РезультатРасчета;
    
КонецФункции
  1. Теперь в модуле формы при открытии мы просто вызываем эту функцию для отображения значения на клиенте:

// В модуле управляемой формы элемента справочника
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Заполняем реквизит формы через вызов функции из модуля менеджера
    ЭтотОбъект.ИмяРеквизитаФормы = Справочники.Контрагенты.ПолучитьДополнительныйПараметрКонтрагента(Объект.Ссылка);
    
КонецПроцедуры
  1. И самое главное — теперь из любого внешнего отчета, обработки или общего модуля мы можем легко получить это значение в одну строчку кода, не обращаясь к форме:

// Вызов из внешней обработки или отчета
НужноеЗначение = Справочники.Контрагенты.ПолучитьДополнительныйПараметрКонтрагента(ВыбраннаяСсылка);

Таким образом, мы полностью разделили интерфейс и данные. Наш код стал чистым, масштабируемым и соответствующим официальным стандартам разработки фирмы «1С».

← На главную