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

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

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

Почему возникает ошибка при записи в элементы формы?

Разберем ситуацию, с которой столкнулся автор темы. В коде была сделана попытка напрямую присвоить значение визуальному элементу формы:


// Ошибочный подход
УсловныйВыбор = ВыборкаДетальныеЗаписи.НаименованиеЗаказа;
ЭтотОбъект.Элементы.НаименованиеЗаказа = УсловныйВыбор;

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

Вторая важная деталь — использование Динамического списка. Форма списка справочника работает на основе этого механизма. Данные в него подгружаются порциями напрямую из базы данных. Мы не можем «дописать» что-то в строку списка программно в цикле, так как список динамически обновляется, и любые наши изменения будут стерты при первом же скроллинге или обновлении формы.

Способ 1. Изменение запроса динамического списка (Рекомендуемый)

Это наиболее правильный и производительный метод. Вместо того чтобы пытаться заполнить данные после открытия формы, мы заставим систему саму выбирать нужные данные из базы при формировании списка. Рассмотрим шаги по реализации:

  1. Откроем форму списка справочника Контрагенты в конфигураторе.
  2. Перейдем на закладку Реквизиты и найдем основной реквизит Список (тип ДинамическийСписок).
  3. В свойствах реквизита установим флаг Произвольный запрос и нажмем ссылку Настройка списка.
  4. В окне конструктора запроса нам нужно соединить основную таблицу справочника с его табличной частью. Проанализируем пример запроса:

ВЫБРАТЬ
    СправочникКонтрагенты.Ссылка КАК Ссылка,
    СправочникКонтрагенты.Код КАК Код,
    СправочникКонтрагенты.Наименование КАК Наименование,
    ЕСТЬNULL(ЗаказыКлиентов.НаименованиеЗаказа, "") КАК НаименованиеЗаказа
ИЗ
    Справочник.Контрагенты КАК СправочникКонтрагенты
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты.ЗаказыКлиентов КАК ЗаказыКлиентов
        ПО СправочникКонтрагенты.Ссылка = ЗаказыКлиентов.Ссылка
            И ЗаказыКлиентов.НомерСтроки = 1

Разберем этот запрос подробнее. Мы используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы в список попали все контрагенты, даже если у них нет заказов. Важнейшее условие здесь — ЗаказыКлиентов.НомерСтроки = 1. Оно гарантирует, что из табличной части будет взята только первая строка, как и требовалось в условии задачи. Функция ЕСТЬNULL поможет избежать пустых значений, если заказов не обнаружено.

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

Способ 2. Использование события ПриАктивизацииСтроки

Если данные из табличной части нужны не для всех строк сразу, а только для той, на которой в данный момент стоит курсор пользователя, рассмотрим вариант с динамическим обновлением отдельного поля. Это снизит нагрузку на сервер при работе с огромными списками.

Сначала создадим обычный реквизит формы (не колонку списка!) с именем ПервыйЗаказКонтрагента (тип Строка). Вынесем его на форму в удобное место.

Далее настроим обработчик события для таблицы формы:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ПервыйЗаказКонтрагента = ПолучитьНаименованиеПервогоЗаказа(ТекущиеДанные.Ссылка);
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьНаименованиеПервогоЗаказа(СсылкаКонтрагента)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    ЗаказыКлиентов.НаименованиеЗаказа КАК НаименованиеЗаказа
        |ИЗ
        |    Справочник.Контрагенты.ЗаказыКлиентов КАК ЗаказыКлиентов
        |ГДЕ
        |    ЗаказыКлиентов.Ссылка = &Ссылка
        |УПОРЯДОЧИТЬ ПО
        |    ЗаказыКлиентов.НомерСтроки";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаКонтрагента);
    Результат = Запрос.Выполнить();
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.НаименованиеЗаказа;
    КонецЕсли;
    Возврат "";
КонецФункции

В этом сценарии мы используем событие ПриАктивизацииСтроки. Как только пользователь выбирает другого контрагента в списке, срабатывает серверная функция, которая быстро находит первый заказ и обновляет значение на экране.

Типичные ошибки при работе с контекстом

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

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

Важные выводы для закрепления материала:

Таким образом, решение проблемы автора темы заключается в переносе логики его запроса непосредственно в настройки динамического списка справочника Контрагенты. Это уберет необходимость в процедуре УсловияНаименованияЗаказа и исключит возникновение ошибок доступа к полям объектов.

← На главную