К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как найти реквизит формы по имени в 1С

Как программно найти реквизит формы по имени в 1С: проверка через ПолучитьРеквизиты, обход коллекции, работа с динамическими реквизитами и типичные ошибки разработчиков.

Задача найти реквизит формы по имени возникает, когда реквизиты создаются динамически, когда модуль формы должен работать с разными наборами данных или когда код пишется универсально — без жёсткой привязки к структуре конкретной формы. Прямого метода вида «НайтиРеквизит(Имя)» у объекта управляемой формы нет, поэтому проверку выполняют через коллекцию реквизитов, которую возвращает метод ПолучитьРеквизиты().

Важно не путать три разные сущности: реквизит формы (данные), элемент формы (отображение на экране, например поле ввода) и реквизит объекта конфигурации (например, реквизит справочника). У каждой сущности свой механизм поиска. В этой статье разобран поиск именно реквизита формы, а также смежные сценарии — поиск элемента формы и реквизита объекта, потому что на практике их часто смешивают.

Ниже приведены рабочие варианты кода для управляемых форм, способ проверки существования реквизита без ошибки, приёмы для динамически создаваемых реквизитов и разбор типичных ошибок, из-за которых поиск возвращает пустой результат.

Что именно вы ищете: реквизит, элемент или реквизит объекта

Прежде чем писать код, определите, к какой сущности относится имя. Реквизит формы — это данные, хранящиеся в форме (колонки «Реквизиты» в редакторе формы конфигуратора). Элемент формы — это визуальный объект: поле ввода, таблица, кнопка. Реквизит объекта — это поле справочника, документа или другого объекта конфигурации, описанное в метаданных.

Смешение этих понятий — главная причина, почему «поиск не работает». Например, обращение ЭтаФорма.Элементы.Найти("Комментарий") найдёт поле ввода на форме, но не скажет ничего о том, существует ли одноимённый реквизит формы. И наоборот: реквизит формы может существовать, но не быть выведенным на форму ни в один элемент.

Базовый способ: перебор коллекции ПолучитьРеквизиты()

Метод ПолучитьРеквизиты() объекта управляемой формы возвращает массив объектов типа РеквизитФормы. У каждого элемента массива есть свойства Имя, ТипЗначения, Путь и другие. Чтобы найти реквизит по имени, переберите массив и сравните свойство Имя с искомой строкой.

Функция НайтиРеквизитФормы(ИмяРеквизита)

Реквизиты = ЭтаФорма.ПолучитьРеквизиты();

Для Каждого Реквизит Из Реквизиты Цикл

Если Реквизит.Имя = ИмяРеквизита Тогда

Возврат Реквизит;

КонецЕсли;

КонецЦикла;

Возврат Неопределено;

КонецФункции

Если функция вернула значение, отличное от Неопределено, реквизит существует, и через найденный объект можно узнать его тип и путь. Само значение реквизита при этом читается обычным обращением: ЭтаФорма[ИмяРеквизита] — обращение по строковому имени через квадратные скобки работает и тогда, когда имя заранее неизвестно.

Учтите, что ПолучитьРеквизиты() без параметра возвращает только реквизиты верхнего уровня. Реквизиты, вложенные внутрь другого реквизита (например, колонки таблицы значений, являющейся реквизитом формы), в этот список не попадают.

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

Как проверить существование реквизита без перебора

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

Функция РеквизитСуществует(ИмяРеквизита)

Попытка

Проверка = ЭтаФорма[ИмяРеквизита];

Возврат Истина;

Исключение

Возврат Ложь;

КонецПопытки;

КонецФункции

У этого приёма есть ограничение: он не отличает реквизит формы от свойства самой формы или от реквизита основного объекта формы. Например, для формы документа обращение ЭтаФорма["Номер"] может успешно выполниться, хотя «Номер» — это реквизит объекта, а не самостоятельный реквизит формы. Если нужна строгая проверка именно реквизита формы, используйте перебор из предыдущего раздела.

Сравнение способов проверки

Перебор ПолучитьРеквизиты()

Точно определяет реквизит формы и даёт его тип и путь. Подходит для универсальных механизмов, но требует цикла.

Попытка/Исключение с ЭтаФорма[Имя]

Короткий код для простой проверки. Не различает реквизит формы, свойство формы и реквизит объекта — для строгих проверок не подходит.

Элементы.Найти(Имя)

Ищет элемент интерфейса (поле, кнопку), а не данные. Используйте, когда нужно управлять видимостью или доступностью поля.

Поиск вложенных реквизитов и колонок таблиц

Когда реквизитом формы является таблица значений или динамический список, её колонки становятся подчинёнными реквизитами. Чтобы найти их, передайте в ПолучитьРеквизиты() путь к родительскому реквизиту в виде строки.

// Колонки таблицы значений "Товары", являющейся реквизитом формы

Колонки = ЭтаФорма.ПолучитьРеквизиты("Товары");

Для Каждого Колонка Из Колонки Цикл

Сообщить(Колонка.Имя + " — " + Колонка.ТипЗначения);

КонецЦикла;

Аналогично работает поиск внутри реквизитов типа «ДанныеФормыСтруктура»: сначала получаете вложенные реквизиты по пути родителя, затем сравниваете имена. Если структура многоуровневая, проверку удобно оформить рекурсивной функцией, которая спускается по каждому реквизиту-контейнеру.

Для реквизитов самого объекта конфигурации (например, реквизита справочника, чья форма открыта) поиск выполняется через метаданные: Метаданные.Справочники.Номенклатура.Реквизиты.Найти("Артикул"). У коллекций метаданных метод Найти() есть, в отличие от коллекции реквизитов формы. Если реквизит не найден, метод вернёт Неопределено.

Работа с динамически созданными реквизитами

Реквизиты, добавленные программно методом ИзменитьРеквизиты(), находятся тем же перебором ПолучитьРеквизиты() — после выполнения изменения они становятся полноценной частью формы. Типовой сценарий: при открытии формы создаётся набор реквизитов по настройкам пользователя, а при обработке данных код должен определить, создан ли уже конкретный реквизит, чтобы не добавлять его повторно.

Если НайтиРеквизитФормы("ДопПоказатель1") = Неопределено Тогда

Добавляемые = Новый Массив;

Добавляемые.Добавить(Новый РеквизитФормы("ДопПоказатель1",

Новый ОписаниеТипов("Число"), , "Показатель 1", Ложь));

ЭтаФорма.ИзменитьРеквизиты(Добавляемые);

КонецЕсли;

Обратите внимание: конструктор Новый РеквизитФормы здесь используется для описания создаваемого реквизита, а не для поиска. Повторный вызов ИзменитьРеквизиты() с уже существующим именем вызовет ошибку, поэтому предварительная проверка перебором обязательна в универсальном коде.

Поиск элемента формы по имени

Если на самом деле требуется найти элемент интерфейса — поле ввода, группу, кнопку или таблицу — используйте коллекцию Элементы управляемой формы. У неё есть штатный метод Найти(), который принимает имя элемента строкой и возвращает либо элемент, либо Неопределено.

Элемент = ЭтаФорма.Элементы.Найти("ТоварыЦена");

Если Элемент <> Неопределено Тогда

Элемент.Видимость = Ложь;

КонецЕсли;

Такой поиск безопасен для универсального кода: если элемента нет, ошибки не произойдёт, просто вернётся Неопределено. Проверка на Неопределено перед обращением к свойствам элемента обязательна — обращение к свойству несуществующего элемента вызовет исключение.

Имя элемента можно посмотреть в конфигураторе: в редакторе формы выделите элемент и откройте палитру свойств — поле «Имя» находится вверху. Для элементов, созданных платформой автоматически (например, стандартные командные панели), имена генерируются платформой и могут отличаться от ожидаемых.

Порядок действий при поиске реквизита
  1. 1
    Определите, что ищете: реквизит формы, элемент формы или реквизит объекта конфигурации
  2. 2
    Для реквизита формы вызовите ЭтаФорма.ПолучитьРеквизиты() и переберите массив, сравнивая свойство Имя
  3. 3
    Для вложенных реквизитов передайте путь родителя в ПолучитьРеквизиты(Путь)
  4. 4
    Для элемента формы используйте ЭтаФорма.Элементы.Найти(Имя) с проверкой на Неопределено
  5. 5
    Для реквизита объекта используйте Метаданные...Реквизиты.Найти(Имя)
  6. 6
    Проверьте результат: обратитесь к значению через ЭтаФорма[Имя] и убедитесь, что тип данных ожидаемый

Типичные ошибки и как их избежать

Самая частая ошибка — регистр и точное написание имени. Встроенный язык 1С нечувствителен к регистру в идентификаторах кода, но сравнение строк внутри цикла зависит от того, как вы сравниваете: оператор = для строк в 1С регистронезависим, однако лишние пробелы или невидимые символы в имени приведут к тому, что совпадения не будет. Имя реквизита копируйте из конфигуратора, а не набирайте вручную.

Вторая ошибка — поиск реквизита объекта среди реквизитов формы. В форме документа реквизиты самого документа доступны через основной реквизит формы (обычно «Объект»), и ПолучитьРеквизиты() вернёт только «Объект», а не «Номер», «Дата» и «Контрагент». Чтобы добраться до них, либо обращайтесь через Объект.Контрагент, либо ищите в метаданных документа.

Третья ошибка — вызов поиска до создания реквизитов. Если реквизиты добавляются в обработчике ПриСозданииНаСервере, то проверка их существования в ПриОткрытии на клиенте сработает корректно, а вот попытка найти их раньше завершения серверного создания даст отрицательный результат. Учитывайте порядок событий формы.

Типичные ошибки
01
Искать реквизит объекта через ПолучитьРеквизиты() формы — в массиве будет только основной реквизит «Объект», поиск даст ложный отрицательный результат
02
Использовать Элементы.Найти() для проверки существования данных — элемент может отсутствовать при существующем реквизите и наоборот
03
Обращаться к ЭтаФорма[Имя] без проверки — при отсутствии реквизита возникнет исключение и прервётся обработка
04
Добавлять динамический реквизит без проверки на дубль — повторный вызов ИзменитьРеквизиты() с тем же именем вызовет ошибку

Как проверить, что поиск сработал правильно

После внедрения функции поиска проверьте её на трёх наборах данных: существующий реквизит верхнего уровня, колонка таблицы-реквизита и гарантированно отсутствующее имя. Для каждого случая результат должен быть предсказуемым: объект реквизита, объект колонки и Неопределено соответственно.

Дополнительно сверьте тип найденного реквизита через свойство ТипЗначения с ожидаемым. Если универсальный код дальше записывает значение в найденный реквизит, несовпадение типов приведёт к ошибке преобразования уже на этапе записи — лучше перехватить проблему раньше.

Контрольные точки

Как проверить результат

Поиск существующего реквизита
Норма

Функция вернула объект с нужным именем и типом

Тревожный признак

Возвращено Неопределено — проверьте точное имя в конфигураторе

Поиск несуществующего имени
Норма

Возвращено Неопределено, исключений нет

Тревожный признак

Возникла ошибка выполнения — где-то есть обращение без проверки

Обращение к значению ЭтаФорма[Имя]
Норма

Значение читается и имеет ожидаемый тип

Тревожный признак

Ошибка обращения — реквизит относится к объекту, а не к форме

FAQ

Можно ли найти реквизит формы по части имени?

Да, внутри цикла по массиву ПолучитьРеквизиты() используйте функцию СтрНайти(Реквизит.Имя, Фрагмент) > 0 вместо точного сравнения. Так удобно собирать, например, все реквизиты с префиксом «Доп» в список для дальнейшей обработки.

Почему ПолучитьРеквизиты() возвращает только один реквизит «Объект»?

Потому что в форме объекта (документа, справочника) все реквизиты самого объекта вложены в основной реквизит формы. Они доступны через Объект.ИмяРеквизита, а их описание ищется в метаданных конфигурации, а не в коллекции реквизитов формы.

Как найти реквизит формы на клиенте, если метод серверный?

Метод ПолучитьРеквизиты() доступен и на клиенте в управляемой форме, поэтому перебор работает в клиентских процедурах без вызова сервера. Ограничение касается только тонкого клиента в некоторых режимах работы с данными — проверяйте директивы компиляции модуля.

Чем отличается поиск в обычной форме от управляемой?

В обычных формах (устаревший режим) структура другая: реквизиты формы перечислены в метаданных формы, а элементы доступны через коллекцию ЭлементыФормы с методом Найти(). Код из этой статьи рассчитан на управляемые формы, которые используются во всех современных конфигурациях.

Как узнать имя реквизита, если форма собрана программно?

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

Бывает ли, что реквизит есть, а ЭтаФорма[Имя] выдаёт ошибку?

Да, если имя совпадает со служебным свойством или если реквизит был удалён вызовом ИзменитьРеквизиты() после того, как вы получили его описание. Всегда выполняйте поиск непосредственно перед использованием, а не кэшируйте результат надолго.

Итог

Что важно запомнить

Реквизит формы ищется перебором массива ЭтаФорма.ПолучитьРеквизиты() со сравнением свойства Имя; вложенные реквизиты — через передачу пути родителя. Элемент интерфейса ищется через Элементы.Найти(), реквизит объекта — через метаданные. Перед обращением к значению всегда проверяйте, что поиск вернул результат, а не Неопределено.