Как автоматически заполнить реквизит на форме при выборе значения из справочника в 1С 8.3

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

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

Анализ типичных ошибок при реализации автозаполнения

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

1. Смешивание понятий "Данные" и "Элементы формы"

В управляемом приложении 1С 8.x существует четкое разделение между данными (реквизитами) и их визуальным отображением (элементами). В коде автора встречается строка: Элементы.Обозначение = Обознач;. Это фундаментальная ошибка. Мы не можем напрямую присвоить значение элементу формы (полю ввода), мы должны изменить реквизит данных, к которому привязано это поле. Если наше поле находится в табличной части, нужно менять значение в строке этой таблицы. Если в шапке — в реквизите Объект.

2. Использование поиска по наименованию

Функция Справочники.Авиотехника.НайтиПоНаименованию(Наименование) является крайне ненадежной. Во-первых, наименования могут дублироваться. Во-вторых, поиск по строке работает значительно медленнее, чем обращение по уникальному идентификатору (ссылке). В управляемых формах поле выбора уже содержит Ссылку на объект, поэтому искать объект заново по тексту нет никакой необходимости.

3. Избыточный контекстный вызов сервера

Автор использует директиву &НаСервере. Это означает, что при каждом изменении запчасти на сервер передается весь контекст формы (все данные всех реквизитов, дерево элементов и т.д.). Для получения одного единственного значения из справочника это крайне непроизводительно. Правильнее использовать &НаСервереБезКонтекста.

Решение №1: Использование возможностей платформы (без кода)

Прежде чем писать программный код, проанализируем ситуацию: нужно ли нам физически записывать "Обозначение" в базу данных или достаточно просто показывать его пользователю для информации? Если нам нужно только отображение, 1С позволяет сделать это вообще без программирования.

  1. Откроем редактор управляемой формы.
  2. В дереве реквизитов найдем наш реквизит (например, Запчасть), который имеет тип ссылки на справочник.
  3. Раскроем "плюсик" слева от реквизита. Платформа покажет все доступные поля этого справочника.
  4. Найдем поле Обозначение и просто перетащим его в левую часть (в дерево элементов формы).
  5. Платформа автоматически создаст поле с путем к данным Объект.Запчасть.Обозначение.

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

Решение №2: Программное заполнение реквизита (Правильный подход)

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

Рассмотрим пример, когда данные находятся в табличной части документа:


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

&НаСервереБезКонтекста
Функция ПолучитьОбозначениеНаСервере(Знач СсылкаНаЗапчасть)
    // Обращаемся напрямую к реквизиту ссылки. 
    // Платформа сама выполнит оптимальный SQL-запрос.
    Возврат СсылкаНаЗапчасть.Обозначение;
КонецФункции

Проанализируем преимущества этого кода:

Решение №3: Использование функций общих модулей (Стандарт БСП)

В современных конфигурациях (таких как УТ 11, ERP, БП 3.0), базирующихся на Библиотеке Стандартных Подсистем (БСП), писать свои функции на сервере для получения одного реквизита часто считается "плохим тоном". Для этого уже существуют готовые инструменты.

Рассмотрим, как упростить код, используя функции общего назначения:


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

Метод ОбщегоНазначения.ЗначениеРеквизитаОбъекта удобен тем, что он универсален, оптимизирован и может вызываться прямо с клиента (в некоторых версиях БСП) или через тонкую серверную обертку. Это делает код чище и понятнее для других разработчиков.

Важные рекомендации по производительности

При реализации подобных механизмов следует помнить о нескольких правилах, которые помогут избежать "тормозов" интерфейса:

  1. Минимизируйте количество вызовов: Если вам нужно получить сразу пять реквизитов (Обозначение, Артикул, Вес, Цена), не делайте пять отдельных вызовов сервера. Создайте одну функцию, которая вернет Структуру со всеми нужными данными.
  2. Избегайте создания объектов: Никогда не используйте Ссылка.ПолучитьОбъект() на сервере только для того, чтобы прочитать реквизит. Это очень тяжелая операция. Обращение через точку Ссылка.Реквизит гораздо быстрее.
  3. Помните о контексте: Если вы все же используете &НаСервере (с контекстом), помните, что после завершения процедуры вся форма будет передана обратно клиенту. Если форма "тяжелая" (много строк в ТЧ), пользователь почувствует задержку.

Выяснив причину ошибок автора и разобрав правильные подходы, мы видим, что эффективная разработка в 1С 8.3 строится на грамотном использовании клиент-серверного взаимодействия и понимании того, как платформа работает с данными. Используйте предложенные методы в своих проектах, и ваши интерфейсы будут работать быстро и надежно.

← На главную