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