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