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