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

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

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

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

Анализ типичных ошибок при работе с управляемой формой

Рассмотрим исходный пример кода, в котором допущен ряд концептуальных ошибок:


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

Проанализируем ключевые проблемы данного подхода:

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

Различие между данными формы и объектом базы данных

Важно понимать разницу между объектами формы и объекта конфигурации на сервере:

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

Способ 1. Использование дополнительного реквизита формы (рекомендуемый вариант)

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

  1. Откроем форму документа в конфигураторе и перейдем на вкладку Реквизиты (правая панель).
  2. Добавим новый реквизит формы с именем ОстатокТовара и типом Число (длина 15, точность 3). Этот реквизит существует только во время открытой формы и не попадает в структуру метаданных документа.
  3. Перетащим реквизит ОстатокТовара в дерево элементов формы (в нужное место интерфейса).
  4. В свойствах созданного элемента укажем флаг ТолькоПросмотр = Истина или установим вид Поле надписи.

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


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

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

Способ 2. Отображение остатка через декорацию (надпись)

Если создание реквизита формы не требуется, можно использовать элемент оформления интерфейса — Декорацию (вид — Надпись):

  1. В дереве элементов формы добавим элемент ДекорацияНадпись с именем НадписьОстаток.
  2. Установим начальный заголовок, например: Остаток: 0.
  3. В коде на клиенте будем динамически менять свойство Заголовок данного элемента.

Посмотрим на пример реализации:


&НаКлиенте
Процедура ОбновитьОтображениеОстатка()
    Стр = Элементы.Товары.ТекущиеДанные;
    Если Стр = Неопределено Тогда
        Элементы.НадписьОстаток.Заголовок = "Остаток: -";
        Возврат;
    КонецЕсли;
    
    Остаток = ПолучитьОстатокНоменклатурыНаСервере(
        Стр.Номенклатура, 
        Объект.СкладОтправитель, 
        Объект.Организация, 
        Объект.Дата
    );
    
    Элементы.НадписьОстаток.Заголовок = "Остаток на складе: " + Формат(Остаток, "ЧДЦ=3");
КонецПроцедуры

Рекомендации по обработке событий

Чтобы отображаемый остаток всегда оставался актуальным для пользователя, вызов процедуры обновления следует привязать к нескольким событиям формы:

  1. ТоварыПриАктивизацииСтроки — для пересчета остатка при перемещении курсора по строкам табличной части.
  2. ТоварыНоменклатураПриИзменении — при выборе другого товара в строке.
  3. СкладОтправительПриИзменении и ДатаПриИзменении — при изменении ключевых реквизитов шапки документа.
← На главную