Разработка и Конфигурация · 11 мин
Как получить данные из формы в 1С
Как получить данные из формы в 1С: работа с реквизитами формы, Элементы, ДанныеФормыВЗначение, обращение к форме из другой формы. Примеры кода и типичные ошибки.
Получение данных из формы — одна из самых частых задач при разработке на платформе 1С:Предприятие 8.3. Форма хранит данные в реквизитах, отображает их через элементы, а разработчику нужно уметь читать эти значения в модуле формы, передавать их на сервер и получать из одной формы данные другой. Ошибки здесь типичны: обращение к несуществующему реквизиту, попытка вызвать серверный метод с клиента, работа с устаревшим объектом после записи.
Ключевой принцип управляемых форм: данные формы и элементы формы — разные вещи. Элемент (поле ввода, таблица) только отображает значение, а сами данные лежат в реквизитах формы. Поэтому читать значения нужно через реквизиты, а не через свойства элементов, иначе при изменении интерфейса код перестанет работать.
Ниже разобраны основные способы: чтение реквизитов в модуле формы, передача данных между клиентом и сервером, преобразование ДанныеФормыВЗначение, получение данных из другой формы и работа с табличными частями на форме.
Чтение реквизитов формы в модуле формы
Самый простой случай — получить значение внутри модуля самой формы. Реквизиты формы доступны напрямую по имени, без обращения к коллекции. Если на форме документа есть основной реквизит Объект, то его поля читаются через точку: Объект.Номенклатура, Объект.СуммаДокумента.
Для дополнительных реквизитов формы (тех, что вы добавили в дереве реквизитов в редакторе формы) обращение такое же — просто по имени. Например, если создан реквизит ВыбранныйСклад, то в коде модуля формы пишется: ТекущийСклад = ВыбранныйСклад; или ЭтаФорма.ВыбранныйСклад.
Когда имя реквизита заранее неизвестно и хранится в переменной, используйте квадратные скобки: ЭтаФорма[ИмяРеквизита]. Это удобно для универсальных обработчиков, которые обходят несколько реквизитов по списку имён.
&НаКлиенте
Процедура КомандаРассчитать(Команда)
// Чтение полей основного реквизита
Сумма = Объект.СуммаДокумента;
Склад = Объект.Склад;
// Чтение дополнительного реквизита формы
Коэффициент = ЭтаФорма.КоэффициентПересчета;
// Чтение по имени из переменной
ИмяРеквизита = "СуммаДокумента";
Значение = Объект[ИмяРеквизита];
КонецПроцедуры
Элементы формы: когда читать через Элементы нельзя
Частая ошибка начинающих — пытаться получить данные через коллекцию Элементы: Элементы.СуммаДокумента.??? У элемента формы нет свойства со значением данных в привычном смысле. У поля ввода есть свойство ТекстРедактирования, но оно возвращает текст, который пользователь ввёл прямо сейчас, ещё до окончания редактирования, и может не совпадать с реальным значением реквизита.
ТекстРедактирования оправдан только в одном сценарии — когда нужно перехватить то, что пользователь набирает в поле в процессе ввода (например, для живого поиска по подстроке). Во всех остальных случаях читайте реквизит: после события ПриИзменении значение уже записано в данные формы.
Через Элементы правильно управлять отображением: видимостью, доступностью, заголовком, списком выбора. Но источником истины для данных остаются реквизиты.
Передача данных между клиентом и сервером
В управляемой форме код делится на клиентский и серверный. На клиенте недоступны запросы к базе и прикладные объекты, поэтому данные формы часто нужно передать на сервер для обработки. Директивы &НаКлиенте, &НаСервере, &НаСервереБезКонтекста определяют, где выполняется процедура.
Простые значения (числа, строки, даты, ссылки) передаются на сервер как параметры процедуры без ограничений. А вот реквизит типа ДанныеФормыСтруктура (например, Объект документа) нельзя просто взять и использовать на сервере как прикладной объект — его нужно преобразовать.
&НаКлиенте
Процедура ЗаполнитьНаСервере(Команда)
ЗаполнитьНаСервереСервер(Объект.Организация, Объект.Дата);
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьНаСервереСервер(Организация, Дата)
// Здесь доступны запросы и менеджеры объектов
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ...";
Запрос.УстановитьПараметр("Организация", Организация);
КонецПроцедуры
В процедуре &НаСервереБезКонтекста реквизиты формы недоступны напрямую — такой метод не «видит» форму. Всё нужное передавайте параметрами. Это ускоряет вызов, так как на сервер не пересылается весь контекст формы.
ДанныеФормыВЗначение и ЗначениеВДанныеФормы
Основной реквизит формы документа или справочника имеет тип ДанныеФормыСтруктура — это не прикладной объект, а его представление в форме. Чтобы на сервере получить полноценный объект (ДокументОбъект, СправочникОбъект) с методами Записать(), используется метод РеквизитФормыВЗначение.
&НаСервере
Процедура ПровестиДокументНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры
Обратное преобразование — ЗначениеВРеквизитФормы — обязательно после изменения объекта, иначе форма продолжит показывать старые данные. Пропуск этого шага — частая причина жалоб «записал, а на форме ничего не изменилось».
Учтите, что РеквизитФормыВЗначение — затратная операция: весь объект сериализуется и пересоздаётся. Если нужно только прочитать пару полей или ссылку, преобразование не требуется — ссылка доступна прямо на клиенте через Объект.Ссылка.
Получение данных из таблицы и табличной части на форме
Табличная часть объекта доступна как коллекция: Объект.Товары. Строки перебираются циклом, значения колонок читаются по имени. Текущую строку, которую выделил пользователь, дают Элементы.Товары.ТекущиеДанные (на клиенте) и Элементы.Товары.ТекущаяСтрока (идентификатор строки).
&НаКлиенте
Процедура ТоварыПриИзменении(Элемент)
Строка = Элементы.Товары.ТекущиеДанные;
Если Строка = Неопределено Тогда
Возврат;
КонецЕсли;
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецПроцедуры
Если таблица на форме — это реквизит типа ДанныеФормыКоллекция (динамический список значений, не привязанный к объекту), работа аналогична: перебор строк, поиск через НайтиСтроки с отбором, добавление через Добавить().
Получение данных из другой формы
Из одной формы получить данные другой можно несколькими способами, выбор зависит от сценария. Самый надёжный — передать данные через параметры при открытии формы и получить результат через оповещение о закрытии или выборе.
При открытии формы через ОткрытьФорму можно передать структуру параметров, а в вызывающей форме подписаться на обработку оповещения. Форма-источник при выборе вызывает ОповеститьОВыборе(Результат), и это значение приходит в обработчик вызывающей формы.
&НаКлиенте
Процедура ВыбратьКонтрагента(Команда)
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораКонтрагента", ЭтотОбъект);
ОткрытьФорму("Справочник.Контрагенты.ФормаВыбора", , ЭтаФорма, , , ,
ОписаниеОповещения, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораКонтрагента(Результат, ДопПараметры) Экспорт
Если Результат <> Неопределено Тогда
Объект.Контрагент = Результат;
КонецЕсли;
КонецПроцедуры
Для уже открытой формы можно получить ссылку на неё через ПолучитьФорму() или через владельца (ЭтаФорма.ВладелецФормы) и прочитать её реквизиты. Этот способ хрупкий: он требует, чтобы форма была открыта, и создаёт жёсткую связь между формами. Предпочтительнее обмен через оповещения (Оповестить / ОбработкаОповещения) — формы остаются независимыми.
Как выбрать способ
Проверка результата и отладка
После получения данных проверяйте их перед использованием. Ссылочные значения проверяйте на пустую ссылку через ЗначениеЗаполнено(), строки таблиц — на Неопределено, числовые поля — на допустимые диапазоны. Не полагайтесь на то, что пользователь заполнил всё корректно.
Для отладки используйте точки останова в конфигураторе: в модуле формы доступны все реквизиты через табло (ЭтаФорма раскрывается в дерево реквизитов). Если реквизит не виден в отладчике — проверьте, что вы смотрите на нужный контекст (клиентский или серверный вызов).
Признак правильной работы: после чтения реквизита значение соответствует тому, что видно на форме; после серверной обработки форма обновляет отображение; после выбора в подчинённой форме данные попадают в основную без перезаписи других полей.
Как проверить результат
Совпадает с отображаемым на форме, тип значения корректный
Пустое значение или строка вместо ожидаемого типа
Форма показывает обновлённые значения
Объект изменён, но форма показывает старое — нет ЗначениеВРеквизитФормы
Обработчик оповещения срабатывает, значение записано
Оповещение не приходит — форма не вызвала ОповеститьОВыборе
Что важно запомнить
Данные формы хранятся в реквизитах, а элементы только отображают их — читайте реквизиты. На сервере прикладной объект получают через РеквизитФормыВЗначение и возвращают через ЗначениеВРеквизитФормы. Между формами данные передают параметрами открытия и оповещениями, а не прямым обращением к чужим реквизитам.
Частые вопросы
Как получить значение поля ввода, которое пользователь ещё редактирует?
Через Элементы.ИмяПоля.ТекстРедактирования — это строка текущего ввода. Учтите, что значение ещё не приведено к типу реквизита: число придёт текстом, и его нужно преобразовывать самостоятельно. Для завершённого ввода используйте событие ПриИзменении и читайте реквизит.
Почему на сервере недоступен реквизит формы?
Скорее всего, процедура объявлена с директивой &НаСервереБезКонтекста — такой метод не имеет доступа к данным формы. Либо смените директиву на &НаСервере, либо передайте нужные значения параметрами из клиентской процедуры.
Как получить ссылку на объект из формы, не открывая объект на сервере?
Ссылка доступна на клиенте напрямую: Объект.Ссылка. Преобразование РеквизитФормыВЗначение для этого не требуется — оно нужно только когда требуется сам объект с методами записи и проведения.
Как прочитать данные строки динамического списка?
Через Элементы.Список.ТекущиеДанные вы получите значения видимых колонок текущей строки. Если нужны поля, не выведенные в список, получите ссылку из ТекущиеДанные.Ссылка и прочитайте объект запросом на сервере.
Можно ли из формы элемента обратиться к форме списка?
Да, через ЭтаФорма.ВладелецФормы, если форма элемента открыта из формы списка. Но надёжнее использовать ОповеститьОбИзменении(Ссылка) после записи — тогда список обновится автоматически, и жёсткой связи между формами не возникнет.
Почему после Записать() на форме старые данные?
Объект был получен через РеквизитФормыВЗначение, изменён и записан, но результат не возвращён в форму. Добавьте ЗначениеВРеквизитФормы(ДокОбъект, "Объект") после записи — тогда форма отобразит актуальное состояние.