Как реализовать множественный выбор и связи "один-ко-многим" в табличной части 1С

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

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

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

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

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


&НаКлиенте
Процедура СотрудникиОценкиНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ОткрытьФорму("Документ.Файл.Форма.ФормаСпискаОценок", , ЭтотОбъект);
КонецПроцедуры

Разберем причину, по которой этот подход не дает ожидаемого результата. Метод ОткрытьФорму действительно откроет указанную форму на экране. Однако открываемая типовая форма (списка или документа) ничего не знает о контексте строки, из которой ее вызвали. Вы можете добавлять туда данные, но они никак не привяжутся к конкретной строке исходного документа. Чтобы данные вернулись в исходный документ, форму необходимо открывать строго в режиме выбора, передавать в нее специальные параметры, а затем перехватывать результат в событии ОбработкаВыбора.

Решение 1: Подчиненная табличная часть (Архитектурный стандарт)

Проанализируем самый грамотный подход с точки зрения проектирования баз данных в 1С. Чтобы связать одну строку главной таблицы с несколькими строками подчиненных данных, нам потребуются две табличные части.

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

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


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

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

Решение 2: Использование объекта "Список значений" и сериализация

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

Создадим реквизит ТЧ с типом Строка (неограниченной длины). Именно в этой строке мы будем хранить массив выбранных данных в "упакованном" виде. Разберем по шагам логику работы:

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

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


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

Решение 3: Множественный выбор из типовой формы списка

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

При вызове метода ОткрытьФорму мы должны передать специальный параметр МножественныйВыбор в структуре параметров. Посмотрим на пример:


&НаКлиенте
Процедура СотрудникиСсылкаНаДокументыНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("МножественныйВыбор", Истина);
    ПараметрыФормы.Вставить("ЗакрыватьПриВыборе", Истина);
    
    ОткрытьФорму("Документ.Файл.ФормаСписка", ПараметрыФормы, Элемент);
КонецПроцедуры

В этом случае, открыв форму списка, пользователь сможет удерживать клавишу Ctrl или Shift, чтобы выделить сразу несколько строк. При нажатии кнопки "Выбрать" платформа сгенерирует событие ОбработкаВыбора в элементе формы, из которого был произведен вызов. Параметр ВыбранноеЗначение в этом событии будет содержать готовый массив ссылок, который мы сможем программно обработать и сохранить (например, через подчиненную ТЧ, как было описано в Решении 1).

Решение 4: Организация простого выпадающего списка в строке

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

Чтобы избежать открытия громоздких дополнительных окон, мы можем настроить элемент управления колонки. Для этого выполним следующие действия:

  1. В свойствах элемента колонки на форме установим флаг КнопкаВыпадающегоСписка = Истина.
  2. Там же обязательно установим свойство РежимВыбораИзСписка = Истина.
  3. В обработчике события ПриНачалеРедактирования (или НачалоВыбора) программно сформируем список выбора.

Посмотрим на реализацию в коде:


&НаКлиенте
Процедура СотрудникиОценкаПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    Элемент.СписокВыбора.Очистить();
    Элемент.СписокВыбора.Добавить(1, "Плохо");
    Элемент.СписокВыбора.Добавить(2, "Удовлетворительно");
    Элемент.СписокВыбора.Добавить(3, "Хорошо");
    Элемент.СписокВыбора.Добавить(4, "Отлично");
КонецПроцедуры

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

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

← На главную