Как исправить ошибку «Поле объекта не обнаружено» при передаче параметров в форму выбора 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью передавать параметры из одной формы в другую. Типичный сценарий — открытие формы выбора справочника с предустановленным отбором или передача параметров для инициализации динамического списка. В этой статье мы подробно разберем, почему возникает популярная ошибка «Поле объекта не обнаружено (Специализация)», проанализируем неочевидные баги в коде и научимся писать стабильный, отказоустойчивый код.

Выясняем причину ошибки: почему не обнаруживается поле объекта?

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


ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Специализация", Параметры.Специализация);

Причина этого кроется в структуре данных, которая передается из вызывающей формы. Посмотрим на код процедуры открытия формы на клиенте:


ПараметрыПередачи = Новый Структура;
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("Специализация", нСтр.Специализация);
СтруктураОтбора.Вставить("Разряд", ВытащитьРазряд(нСтр.Наименование));
ПараметрыПередачи.Вставить("Отбор", СтруктураОтбора);

ОткрытьFormу("Справочник.Сотрудники.ФормаВыбора", ПараметрыПередачи, Элементы.Работы);

Обратите внимание на то, как именно упаковываются параметры. Создается общая структура ПараметрыПередачи. В нее вкладывается другая структура — СтруктураОтбора — под ключом "Отбор".

Когда управление передается на сервер в форму выбора, платформа считывает переданную структуру в объект Параметры. В итоге структура параметров на сервере выглядит следующим образом:

Именно поэтому при попытке обратиться напрямую к Параметры.Специализация платформа 1С генерирует вполне логичное исключение: «Поле объекта не обнаружено (Специализация)».

Рассмотрим два способа исправления этой архитектурной нестыковки.

---

Решение А. Чтение параметров через структуру «Отбор»

Если структура передаваемых данных должна остаться прежней (например, если платформа должна автоматически применить стандартный отбор к динамическому списку), нам необходимо скорректировать чтение параметров на сервере. Обращаться к ним нужно через промежуточное свойство Отбор:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем наличие вложенной структуры отбора
    Если Параметры.Свойство("Отбор") И ТипЗнч(Параметры.Отбор) = Тип("Структура") Тогда
        
        СпециализацияЗначение = Неопределено;
        Если Параметры.Отбор.Свойство("Специализация", СпециализацияЗначение) Тогда
            ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Специализация", СпециализацияЗначение);
        КонецЕсли;
        
        РазрядЗначение = Неопределено;
        Если Параметры.Отбор.Свойство("Разряд", РазрядЗначение) Тогда
            ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Разряд", РазрядЗначение);
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

---

Решение Б. Передача параметров напрямую (рекомендуемый подход)

Зачастую разработчики путают стандартный механизм отбора платформы и кастомные параметры запроса динамического списка.

Если в вашем динамическом списке ВыборСотрудников используется произвольный запрос, в тексте которого жестко прописаны параметры (например, Где Специализация = &Специализация), то заворачивать эти параметры в структуру Отбор нет никакого практического смысла. Фильтры "Отбора" накладываются платформой динамически поверх запроса, тогда как "Параметры запроса" должны передаваться напрямую.

Давайте изменим клиентский код так, чтобы параметры передавались на верхнем уровне структуры:


&НаКлиенте
Процедура Подбор(Команда)
    
    // Получаем текущую строку таблицы
    нСтр = Элементы.Работы.ТекущиеДанные;
    
    // Проверяем на Неопределено (подробно разберем этот важный шаг ниже!)
    Если нСтр = Неопределено Тогда
        ПоказатьПредупреждение(, "Пожалуйста, выберите строку в таблице работ.");
        Возврат;
    КонецЕсли;
    
    // Формируем параметры напрямую без лишней вложенности
    ПараметрыПередачи = Новый Структура;
    ПараметрыПередачи.Вставить("Специализация", нСтр.Специализация);
    ПараметрыПередачи.Вставить("Разряд", ВытащитьРазряд(нСтр.Наименование));
    
    // Открываем форму выбора
    ОткрытьФорму("Справочник.Сотрудники.ФормаВыбора", ПараметрыПередачи, Элементы.Работы);
    
КонецПроцедуры

При таком подходе на сервере в форме выбора восстановится работоспособность исходного кода, так как свойства будут находиться на верхнем уровне объекта Параметры:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Теперь параметры доступны напрямую!
    ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Специализация", Параметры.Специализация);
    ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Разряд", Параметры.Разряд);
    
КонецПроцедуры

---

Анализ скрытых ошибок и уязвимостей исходного кода

Решение проблемы с передачей структуры — это лишь верхушка айсберга. Исходный код автора содержит несколько критических уязвимостей и логических ошибок, которые обязательно приведут к нестабильной работе программы в реальной эксплуатации. Разберем их подробно.

1. Бессмысленный цикл по строкам табличной части

Посмотрим на этот фрагмент в клиентской процедуре:


Для Каждого вЗнч Из Объект.Работы Цикл
    нСтр = Элементы.Работы.ТекущиеДанные;
КонецЦикла;

Этот цикл выполняет абсолютно бесполезную работу по двум причинам:

  1. Переменная цикла вЗнч никак не используется внутри тела цикла.
  2. На каждом шаге переменной нСтр присваивается одно и то же значение — текущая выделенная строка на форме (ТекущиеДанные). Программа просто перезаписывает одну и ту же переменную столько раз, сколько строк в вашей таблице.

Решение: Данный цикл необходимо полностью удалить. Нам нужна только та строка, на которой сейчас сфокусирован пользователь.

2. Опасность аварийного завершения из-за отсутствия проверки на Неопределено

Если пользователь нажмет кнопку «Подбор» в пустой таблице или снимет выделение со строк, свойство Элементы.Работы.ТекущиеДанные вернет значение Неопределено.

В этом случае при попытке выполнить код нСтр.Специализация система немедленно завершит работу с ошибкой «Поле объекта не обнаружено (Специализация)» прямо на клиенте. Пользователь увидит неприятное системное окно сбоя.

Решение: Всегда проверяйте возвращаемое значение на Неопределено перед обращением к свойствам строки.

3. Небезопасное чтение параметров на сервере

Даже если в процедуре открытия параметры передаются корректно, жесткое обращение к ним на сервере (Параметры.Специализация) является грубой ошибкой проектирования.

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

Решение: Всегда используйте метод Свойство() для безопасной проверки наличия ключей в структурах.

4. Локальные переменные или реквизиты формы?

Обратите внимание на строки кода в серверном обработчике:


Специализация = Параметры.Специализация;
Разряд = Параметры.Разряд;

Здесь кроется важный нюанс области видимости в 1С:

---

Итоговый эталонный вариант реализации

Теперь объединим все наши архитектурные и логические исправления в красивое, отказоустойчивое решение, написанное по всем стандартам разработки фирмы "1С".

Код вызывающей формы (клиентская часть):


&НаКлиенте
Процедура Подбор(Команда)
    
    // 1. Получаем текущие данные таблицы формы
    ТекущаяСтрока = Элементы.Работы.ТекущиеДанные;
    
    // 2. Обязательно проверяем, выбрана ли строка пользователем
    Если ТекущаяСтрока = Неопределено Тогда
        ПоказатьПредупреждение(, "Пожалуйста, выберите строку в таблице работ для выполнения подбора!");
        Возврат;
    КонецЕсли;
    
    // 3. Безопасно формируем структуру параметров для передачи
    ПараметрыПередачи = Новый Структура;
    ПараметрыПередачи.Вставить("Специализация", ТекущаяСтрока.Специализация);
    
    // Извлекаем разряд из наименования с помощью нашей функции
    РазрядЗначение = ВытащитьРазряд(ТекущаяСтрока.Наименование);
    ПараметрыПередачи.Вставить("Разряд", РазрядЗначение);
    
    // 4. Открываем форму выбора справочника "Сотрудники"
    ОткрытьФорму("Справочник.Сотрудники.ФормаВыбора", ПараметрыПередачи, Элементы.Работы);
    
КонецПроцедуры

Код вызываемой формы выбора (серверная часть):


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Инициализируем переменные дефолтными (пустыми) значениями
    ВыбраннаяСпециализация = Справочники.Специализации.ПустаяСсылка();
    ВыбранныйРазряд = 0;
    
    // Безопасно проверяем и считываем параметры, переданные в форму
    Если Параметры.Свойство("Специализация", ВыбраннаяСпециализация) Тогда
        ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Специализация", ВыбраннаяСпециализация);
    КонецЕсли;
    
    Если Параметры.Свойство("Разряд", ВыбранныйРазряд) Тогда
        ВыборСотрудников.Параметры.УстановитьЗначениеПараметра("Разряд", ВыбранныйРазряд);
    КонецЕсли;
    
    // Если на форме созданы реквизиты для хранения этих значений, заполняем их через контекст
    ЭтаФорма.Специализация = ВыбраннаяСпециализация;
    ЭтаФорма.Разряд = ВыбранныйРазряд;
    
КонецПроцедуры

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

← На главную