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

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

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

Проблема: ограничение ссылочного типа

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

Решение №1: Программное формирование списка выбора (событие НачалоВыбора)

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

Во-первых, в форме документа для поля ввода Достопримечательность необходимо создать обработчик события НачалоВыбора. Рассмотрим пример кода:


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

&НаСервереБезКонтекста
Функция ПолучитьСписокСтрокТЧ(СсылкаНаГород)
    
    Список = Новый СписокЗначений;
    
    // Извлекаем данные из табличной части справочника
    Для Каждого СтрокаТЧ Из СсылкаНаГород.Достопримечательности Цикл
        Список.Добавить(СтрокаТЧ.Наименование);
    КонецЦикла;
    
    Возврат Список;
    
КонецФункции

&НаКлиенте
Процедура ПослеВыбораДостопримечательности(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныйЭлемент <> Неопределено Тогда
        Объект.Достопримечательность = ВыбранныйЭлемент.Значение;
    КонецЕсли;
    
КонецПроцедуры

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

Решение №2: Использование события ОбработкаПолученияДанныхВыбора

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

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

Решение №3: Переход к правильной архитектуре (Подчиненный справочник)

Как отмечают опытные разработчики, хранение важных данных в табличных частях справочников для последующей ссылки на них — это архитектурная ошибка. Достопримечательность должна быть отдельным объектом (элементом справочника), чтобы на неё можно было ссылаться через GUID. Это обеспечит целостность данных: если вы переименуете "Эрмитаж" в "Государственный Эрмитаж", во всех документах информация обновится автоматически.

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

  1. Создадим новый справочник Достопримечательности.
  2. В свойствах нового справочника установим владельца — справочник Города.
  3. Напишем и запустим следующий код (в обработке или консоли кода):

ВыборкаГородов = Справочники.Города.Выбрать();

Пока ВыборкаГородов.Следующий() Цикл
    
    // Проходим по строкам табличной части
    Для Каждого СтрокаТЧ Из ВыборкаГородов.Достопримечательности Цикл
        
        // Создаем новый элемент в подчиненном справочнике
        НовыйЭлемент = Справочники.Достопримечательности.СоздатьЭлемент();
        НовыйЭлемент.Наименование = СтрокаТЧ.Название;
        НовыйЭлемент.Владелец = ВыборкаГородов.Ссылка;
        
        Попытка
            НовыйЭлемент.Записать();
        Исключение
            Сообщить("Ошибка при записи: " + ОписаниеОшибки());
        КонецПопытки;
        
    КонецЦикла;
    
КонецЦикла;

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

Сравнение подходов

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

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

← На главную