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