При разработке на управляемых формах часто возникает задача позволить пользователю выбрать не один элемент справочника, а сразу несколько, и автоматически добавить их в табличную часть документа или обработки. Начинающие разработчики часто сталкиваются с тем, что форма выбора открывается, элементы выделяются, но после нажатия кнопки «Выбрать» ничего не происходит или заполняется только одна строка. Рассмотрим подробно, почему это происходит и как правильно написать код для решения этой задачи.
Проанализируем ситуацию: когда мы включаем режим МножественныйВыбор в параметрах формы, платформа 1С меняет тип возвращаемого значения. Если при обычном выборе процедура ОбработкаВыбора получает одиночную ссылку (например, СправочникСсылка.Дисциплины), то при множественном выборе она получает объект типа Массив, содержащий эти ссылки.
Попытка напрямую присвоить массив реквизиту табличной части, который ожидает ссылку, — Строка.Дисциплина = ВыбранноеЗначение; — приведет к тому, что система не сможет сопоставить типы, и ячейка останется пустой. Выясним, как правильно обработать этот массив.
Для начала нам нужно правильно открыть форму выбора. Это делается в обработчике события НачалоВыбора для элемента формы (ячейки табличной части). Рассмотрим код:
&НаКлиенте
Процедура ДисциплиныДисциплинаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Отключаем стандартный механизм выбора, так как будем открывать форму программно
СтандартнаяОбработка = Ложь;
// Формируем структуру параметров для формы выбора
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("МножественныйВыбор", Истина); // Разрешаем выделение нескольких строк
ПараметрыФормы.Вставить("ЗакрыватьПриВыборе", Истина); // Закрывать форму после нажатия кнопки «Выбрать»
// Открываем форму выбора справочника «Дисциплины»
// Параметр «Элемент» указывает, что результат вернется в этот же элемент формы
ОткрытьФорму("Справочник.Дисциплины.Форма.ФормаВыбора", ПараметрыФормы, Элемент);
КонецПроцедуры
Важный нюанс: Обратите внимание на параметр Элемент в функции ОткрытьФорму. Он связывает открываемую форму выбора с текущим полем ввода. Именно благодаря этому после выбора сработает событие ОбработкаВыбора у этого поля.
Теперь разберем, как принять массив выбранных элементов и распределить их по строкам табличной части. Это происходит в процедуре ОбработкаВыбора.
&НаКлиенте
Процедура ДисциплиныДисциплинаОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Обязательно отключаем стандартную обработку, чтобы платформа не пыталась
// сама записать массив в текущую ячейку
СтандартнаяОбработка = Ложь;
// Проверяем, что нам вернулся массив (защита от непредвиденных ситуаций)
Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
// Рассмотрим цикл обхода выбранных элементов
Для Каждого ЭлементСписка Из ВыбранноеЗначение Цикл
// Добавляем новую строку в табличную часть «Дисциплины»
НоваяСтрока = Объект.Дисциплины.Добавить();
// Заполняем реквизит «Дисциплина» ссылкой из массива
НоваяСтрока.Дисциплина = ЭлементСписка;
КонецЦикла;
ИначеЕсли ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
// Если вдруг был выбран всего один элемент (не массив)
НоваяСтрока = Объект.Дисциплины.Добавить();
НоваяСтрока.Дисциплина = ВыбранноеЗначение;
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию с текущей строкой. Если пользователь нажал на выбор в уже существующей пустой строке, код выше просто добавит новые строки ниже, оставив первую строку пустой. Чтобы этого избежать, можно сначала заполнить текущую строку, а остальные добавлять. Но на практике чаще всего просто очищают пустую строку или используют подбор.
В процессе обсуждения выяснилось, что реквизит Дисциплина может иметь составной тип данных. Это критический момент. Если в конфигураторе для реквизита табличной части не указан тип СправочникСсылка.Дисциплины, то при программном присвоении НоваяСтрока.Дисциплина = ЭлементСписка; значение не будет установлено (останется Неопределено).
Что нужно проверить:
Дисциплины.Использование события ОбработкаВыбора — это классический метод, но в современной разработке (особенно для веб-клиента) рекомендуется использовать асинхронный вызов с ОписаниеОповещения. Это делает код более гибким и позволяет избежать привязки к конкретному элементу формы.
Посмотрим, как переписать наше решение по стандартам разработки 1С:
&НаКлиенте
Процедура ПодборДисциплин(Команда)
// Создаем описание процедуры, которая выполнится после закрытия формы выбора
Оповещение = Новый ОписаниеОповещения("ПослеВыбораДисциплин", ЭтотОбъект);
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("МножественныйВыбор", Истина);
// Открываем форму программно, передавая ОписаниеОповещения
ОткрытьФорму("Справочник.Дисциплины.Форма.ФормаВыбора", ПараметрыФормы, ЭтаФорма,,,, Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораДисциплин(РезультатВыбора, ДополнительныеПараметры) Экспорт
// Если пользователь закрыл форму без выбора, РезультатВыбора будет Неопределено
Если РезультатВыбора = Неопределено Тогда
Возврат;
КонецЕсли;
// Обрабатываем результат (массив или одиночное значение)
Если ТипЗнч(РезультатВыбора) = Тип("Массив") Тогда
МассивЗначений = РезультатВыбора;
Иначе
МассивЗначений = Новый Массив;
МассивЗначений.Добавить(РезультатВыбора);
КонецЕсли;
Для Каждого СсылкаДисциплина Из МассивЗначений Цикл
СтрокаТЧ = Объект.Дисциплины.Добавить();
СтрокаТЧ.Дисциплина = СсылкаДисциплина;
КонецЦикла;
КонецПроцедуры
Этот метод считается более «чистым», так как логика добавления строк четко отделена от интерфейсных событий конкретного поля ввода. Мы можем вызвать процедуру ПодборДисциплин кнопкой над табличной частью, что для пользователя часто удобнее, чем выбирать элементы по одному из ячейки.
Если ваш код «не работает», проверьте следующие пункты:
Во-первых, убедитесь, что вы не забыли СтандартнаяОбработка = Ложь в ОбработкаВыбора.
Во-вторых, проверьте в отладчике, что ВыбранноеЗначение действительно является массивом.
В-третьих, убедитесь, что типы в массиве и типы реквизита табличной части совпадают на 100%. Помните, что СправочникОбъект и СправочникСсылка — это разные вещи, и в табличную часть всегда записывается именно Ссылка.