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