При разработке сложных интерфейсов на управляемых формах 1С мы часто сталкиваемся с ситуациями, когда элементы формы создаются программно. Одной из наиболее трудных задач в этом случае является манипуляция данными внутри обработчика события ОбработкаВыбора. Типичный сценарий: поле ввода связано с конкретной строкой технической таблицы (через индекс), которая даже не выведена на форму. Нам нужно не просто заменить текст в поле выбранным значением, а, например, дописать его через запятую.
Ситуация осложняется тем, что свойство ПутьКДанным доступно на клиенте только для чтения, а ТекстРедактирования и вовсе не позволяет изменять себя напрямую. В этой статье мы разберем несколько стратегий решения этой задачи: от визуальных «хаков» до архитектурно правильных подходов с использованием метаданных элементов.
Рассмотрим ситуацию, когда нам нужно быстро изменить содержимое поля, не переходя на сервер и не пытаясь вычислить, к какому именно индексу таблицы привязано это поле. Мы можем использовать свойство ВыделенныйТекст. Логика заключается в том, что если программно выделить весь текст в поле, то присвоение значения свойству ВыделенныйТекст фактически заменит всё содержимое поля.
Проанализируем пример кода, который позволяет реализовать добавление выбранного значения к уже существующему тексту:
&НаКлиенте
Процедура ЭлементКомментарийОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Отключаем стандартную подстановку значения платформой
СтандартнаяОбработка = Ложь;
// Получаем текущее содержание поля через ТекстРедактирования
ТекущийТекст = Элемент.ТекстРедактирования;
Если ЗначениеЗаполнено(ТекущийТекст) Тогда
// Программным выделением охватываем весь имеющийся текст
// Параметры: Начало (1) и Конец (длина + 1)
Элемент.УстановитьГраницыВыделения(1, СтрДлина(ТекущийТекст) + 1);
// Формируем новую строку: старое значение + разделитель + новое
НовоеЗначение = ТекущийТекст + " , " + Строка(ВыбранноеЗначение);
Иначе
НовоеЗначение = Строка(ВыбранноеЗначение);
КонецЕсли;
// Заменяем выделенный текст (то есть всё поле) на нашу новую строку
Элемент.ВыделенныйТекст = НовоеЗначение;
// Важно: чтобы платформа зафиксировала изменение в данных реквизита,
// подменим само ВыбранноеЗначение, если это необходимо для дальнейшей логики
ВыбранноеЗначение = НовоеЗначение;
КонецПроцедуры
Плюсы этого метода: Работает полностью на клиенте, не требует знания структуры данных и имен реквизитов.
Минусы: Может вызвать визуальное «мигание» выделения и не всегда стабильно ведет себя в веб-клиенте.
Разберем более надежный подход. Если элементы создаются программно, мы можем заложить информацию о пути к данным в само имя элемента. Например, при создании поля присваивать ему имя вида ПолеТекста_Индекс_5, где 5 — это номер строки в вашей таблице.
В обработчике ОбработкаВыбора мы сможем легко вычислить, с какой строкой работаем, и напрямую обратиться к данным объекта. Выясним, как это выглядит на практике:
&НаКлиенте
Процедура ДинамическийЭлементОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Допустим имя элемента: "ИнфоПоле_12", где 12 - индекс строки в Объект.ТехТаблица
ИмяЭлемента = Элемент.Имя;
ПозицияРазделителя = СтрНайти(ИмяЭлемента, "_", НаправлениеПоиска.СКонца);
ИндексСтроки = Число(Сред(ИмяЭлемента, ПозицияРазделителя + 1));
// Обращаемся напрямую к коллекции данных формы
СтрокаДанных = Объект.ТехТаблица[ИндексСтроки];
Если ЗначениеЗаполнено(СтрокаДанных.Комментарий) Тогда
СтрокаДанных.Комментарий = СтрокаДанных.Комментарий + "; " + Строка(ВыбранноеЗначение);
Иначе
СтрокаДанных.Комментарий = Строка(ВыбранноеЗначение);
КонецЕсли;
КонецПроцедуры
Этот способ считается наиболее «чистым», так как мы работаем непосредственно с данными (моделью), а не с визуальным представлением элемента.
Если изменить логику именования элементов невозможно, нам придется выяснить, на что ссылается элемент, обратившись к серверному контексту формы. На сервере коллекция Элементы предоставляет полный доступ к свойству ПутьКДанным.
Рассмотрим комбинированный метод. Сначала мы идем на сервер, получаем строку пути, а затем используем ее для доступа к значению. Проанализируем ситуацию, когда путь имеет сложный вид: Объект.Таблица[0].Поле.
&НаСервере
Функция ПолучитьПутьИЗначение(ИмяЭлемента)
// На сервере ПутьКДанным доступен
Путь = Элементы[ИмяЭлемента].ПутьКДанным;
Возврат Путь;
КонецФункции
&НаКлиенте
Процедура ЭлементОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ПутьКДанным = ПолучитьПутьИЗначение(Элемент.Имя);
// Для обращения к данным по строковому пути можно использовать
// нехитрый парсинг или серверный вызов с Выполнить()
ОбновитьДанныеПоПути(ПутьКДанным, ВыбранноеЗначение);
КонецПроцедуры
Для обновления данных по динамическому пути на сервере удобно использовать оператор Выполнить. Это позволяет избежать написания сложных парсеров для разбора квадратных скобок в строках типа Объект.Список[2].Наименование.
&НаСервере
Процедура ОбновитьДанныеПоПути(Путь, Добавка)
// Пример безопасного динамического присвоения (упрощенно)
ТекущееЗначение = "";
Выполнить("ТекущееЗначение = " + Путь);
НовоеЗначение = ТекущееЗначение + ?(Путь = "", "", ", ") + Добавка;
// Присваиваем обратно
Выполнить(Путь + " = НовоеЗначение");
КонецПроцедуры
Проанализируем несколько критически важных моментов, которые помогут избежать ошибок при реализации подобных механизмов:
Ложь, если вы самостоятельно меняете значение реквизита. Если этого не сделать, платформа после завершения вашего кода выполнит стандартное действие — затрет ваш результат тем значением, которое было выбрано пользователем изначально.ВыбранноеЗначение может быть не только строкой, но и ссылкой, числом или структурой (в зависимости от типа данных поля). Перед конкатенацией всегда приводите его к строке функцией Строка().Подсказка, а в событии ПриИзменении склеивать новое значение со старым. Однако ОбработкаВыбора дает больше контроля над процессом подстановки.УстановитьГраницыВыделения, убедитесь, что элемент находится в фокусе, иначе некоторые методы работы с выделением могут проигнорировать вызов.Подводя итог, можно сказать, что выбор метода зависит от архитектуры вашей формы. Если вы сами создаете элементы — используйте именование с индексами. Если форма чужая — используйте метод с ВыделенныйТекст или серверное получение ПутьКДанным.