Как автоматически заполнить подчиненные справочники в табличной части при выборе основного значения?

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

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

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

Анализ проблемы: почему данные не отображаются на форме?

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

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

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

Решение 1: Использование события ПриИзменении и ТекущиеДанные

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

Рассмотрим пошагово реализацию на клиенте и сервере:


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

    // Вызываем серверную функцию для получения данных подчиненных справочников
    // Передаем ссылку на выбранного сотрудника
    СтруктураДанных = ПолучитьДанныеПодчиненныхСправочников(ТекСтрокаТЧ.Сотрудник);
    
    // Заполняем реквизиты строки из полученной структуры
    ТекСтрокаТЧ.Спр1 = СтруктураДанных.Ссылка1;
    ТекСтрокаТЧ.Спр2 = СтруктураДанных.Ссылка2;

КонецПроцедуры

В данном примере мы используем Элементы.ТабличнаяЧасть.ТекущиеДанные. Это наиболее эффективный способ доступа к данным активной строки на клиенте. В отличие от метода НайтиПоИдентификатору, он не требует дополнительных серверных вызовов и поиска в коллекции.

Решение 2: Оптимизация серверной части через запрос

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


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

Обратите внимание на использование директивы &НаСервереБезКонтекста. Это критически важно для производительности: при вызове такой функции на сервер не передается вся форма (данные всех реквизитов), а только параметры функции. Это значительно ускоряет отклик интерфейса.

Связи параметров выбора: фильтрация vs автозаполнение

Важно различать два механизма: Связи параметров выбора и программное заполнение. В настройках реквизитов табличной части часто устанавливают отбор по владельцу (например, Отбор.Владелец(Объект.ТабличнаяЧасть.Сотрудник)).

Проанализируем разницу:

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

Если код отрабатывает, данные в отладчике верные, но в поле ТекСтрокаТЧ.Спр1 значение всё равно не записывается, проверим типы данных. В 1С 8.3 строгая типизация в реквизитах формы. Если колонка табличной части имеет тип СправочникСсылка.Спр1Вид, а ваша функция по ошибке возвращает объект (СправочникОбъект) или ссылку другого справочника, платформа просто проигнорирует присвоение или выдаст ошибку.

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

Рекомендации по улучшению интерфейса

Чтобы ваше решение выглядело профессионально, рассмотрим дополнительные нюансы:

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

Используя предложенные методы работы с ПриИзменении и эффективными серверными вызовами &НаСервереБезКонтекста, вы добьетесь быстрой и стабильной работы интерфейса управляемого приложения, минимизировав ошибки синхронизации данных между клиентом и сервером.

← На главную