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

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

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

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

Различие между физическими реквизитами и путями данных

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

  1. Реквизит связанного справочника: Если в поле «Путь к данным» элемента формы указано что-то вроде Объект.Товары.Номенклатура.ЕдиницаИзмерения, то это поле является виртуальным. Оно лишь отображает значение из ссылки.
  2. Собственный реквизит формы: Если вы добавили колонку непосредственно в структуру реквизитов формы (синий значок в дереве реквизитов), такие данные не попадут в модуль объекта автоматически при записи.

Способ 1. Получение значения через ссылку (через точку)

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Для Каждого ТекСтрока Из ЭтотОбъект.Товары Цикл
        
        // Получаем значение через точку от ссылки
        Если НЕ ЗначениеЗаполнено(ТекСтрока.Номенклатура.ЕдиницаИзмерения) Тогда
            ТекстСообщения = СтрШаблон("В строке № %1 не заполнена единица измерения в карточке номенклатуры!", ТекСтрока.НомерСтроки);
            ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , "Объект.Товары[" + (ТекСтрока.НомерСтроки - 1) + "].Номенклатура");
            Отказ = Истина;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важное предостережение: Обращение «через точку» от ссылки в цикле вызывает отдельный запрос к базе данных на каждой итерации (проблема N+1 запроса). Если в документе сотни строк, это существенно замедлит проведение. Рассмотрим далее, как оптимизировать этот процесс.

Способ 2. Использование запроса для массовой проверки (Оптимальный)

Проанализируем ситуацию с точки зрения производительности. Вместо обращения в цикле, правильнее один раз получить все необходимые данные из связанных справочников одним запросом.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДокТовары.НомерСтроки КАК НомерСтроки,
    |	ДокТовары.Номенклатура КАК Номенклатура,
    |	ДокТовары.Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
    |ИЗ
    |	Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
    |ГДЕ
    |	ДокТовары.Ссылка = &Ссылка
    |	И ДокТовары.Номенклатура.ЕдиницаИзмерения = ЗНАЧЕНИЕ(Справочник.ЕдиницыИзмерения.ПустаяСсылка)";

Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();

Если НЕ РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        // Сообщаем пользователю об ошибке
        Отказ = Истина;
    КонецЦикла;
КонецЕсли;

Способ 3. Передача «чистых» реквизитов формы через ДополнительныеСвойства

Выясним, как поступить, если реквизит вообще не привязан к справочнику, а существует только на форме. Модуль объекта (где происходит проведение) ничего не знает о контексте формы. Чтобы передать данные «с экрана» в логику проведения, воспользуемся коллекцией ДополнительныеСвойства.

Разберем по шагам:

  1. В модуле формы в обработчике ПередЗаписьюНаСервере подготовим данные.
  2. В модуле объекта в ОбработкаПроведения прочитаем эти данные.

Пример кода в модуле формы:


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

Пример кода в модуле объекта:


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

Способ 4. Стандартный механизм «ОбработкаПроверкиЗаполнения»

Посмотрим на ситуацию под другим углом. Если нужно просто проверить заполненность, в платформе 1С предусмотрено событие ОбработкаПроверкиЗаполнения. Оно вызывается перед записью и проведением.

Если реквизит выведен через точку от номенклатуры, стандартная проверка ПроверяемыеРеквизиты.Добавить() не сработает для колонки ТЧ, так как путь ведет к другому объекту (справочнику). В этом случае проверку нужно описывать вручную внутри этого же обработчика, обходя коллекцию ЭтотОбъект.Товары аналогично Способу 1.

Однако, если проверка должна срабатывать только при работе через форму, этот код можно разместить в модуле формы:


&НаСервере
Процедура ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)
    
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        // Здесь нам доступны даже те колонки, которых нет в объекте, 
        // но которые есть в реквизитах формы
        Если НЕ ЗначениеЗаполнено(СтрокаТЧ.МойРеквизитФормы) Тогда
            // Сообщить об ошибке
            Отказ = Истина;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Рекомендации по реализации

Проанализировав все способы, подведем итог:

  1. Для реквизитов через точку: Используйте запрос в ОбработкеПроведения для массовой проверки. Это самый быстрый и надежный способ, который сработает даже при проведении документа программно или через групповую обработку.
  2. Для визуальной подсветки: Используйте свойство элемента формы «Автоотметка незаполненного». Это не заменит программную проверку, но поможет пользователю сразу увидеть пустые поля.
  3. Для данных, существующих только на форме: Используйте связку ПередЗаписьюНаСервере и ДополнительныеСвойства. Помните, что при программном создании документа (без открытия формы) эти данные заполнены не будут, поэтому в модуле объекта стоит предусмотреть поведение «по умолчанию».
  4. UX (User Experience): Проверки на клиенте (в ПередЗаписью) позволяют пользователю получить ответ мгновенно, не дожидаясь серверного вызова, что делает интерфейс более «отзывчивым».

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

← На главную