К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как обратиться к табличной части на форме 1С

Как обратиться к табличной части на форме 1С: обход строк, текущие данные, программное изменение реквизитов, работа в управляемых и обычных формах.

Табличная часть — один из самых часто используемых элементов документов и справочников в 1С, и умение правильно обратиться к ней на форме определяет качество доработок. Ошибки здесь типичны: разработчик обращается к неправильному объекту, работает с копией данных вместо самой строки или получает падение кода из-за контекста «клиент–сервер».

Способ обращения зависит от типа формы (управляемая или обычная), от места выполнения кода (на клиенте или на сервере) и от того, что требуется: прочитать данные, изменить строку или перебрать все записи. Ниже разобраны основные сценарии с готовыми примерами кода на встроенном языке 1С.

Материал ориентирован на платформу 1С:Предприятие 8.3 с управляемыми формами — именно они используются в современных типовых конфигурациях. Отдельно рассмотрены особенности обычных форм, которые ещё встречаются в старых решениях.

Где «живёт» табличная часть на управляемой форме

На управляемой форме документа табличная часть существует в двух ипостасях, и путать их нельзя. Первая — данные: коллекция строк, доступная через реквизит формы Объект, например Объект.Товары. Это данные самого документа, с ними работают при чтении и записи.

Вторая ипостась — элемент формы, то есть визуальная таблица, которую видит пользователь. Она доступна через Элементы.Товары и нужна, когда требуется узнать, какая строка выделена, установить отбор, управлять видимостью колонок или получить текущие данные строки.

Правило простое: если нужны данные — обращайтесь к Объект.ИмяТабличнойЧасти, если нужно состояние интерфейса (текущая строка, выделение) — к Элементы.ИмяТабличнойЧасти. Смешение этих контекстов — самая частая причина ошибок «Поле объекта не обнаружено».

Перебор и чтение строк табличной части

Классическая задача — пройтись по всем строкам и что-то посчитать или проверить. На клиенте и на сервере без контекста это делается одинаково, через цикл Для Каждого:

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Если СтрокаТовара.Количество = 0 Тогда

Сообщить("В строке " + СтрокаТовара.НомерСтроки + " не указано количество");

КонецЕсли;

КонецЦикла;

Обратите внимание: переменная цикла — это не копия, а ссылка на строку коллекции. Изменения, внесённые через СтрокаТовара.Цена = 100, сразу попадают в данные объекта и отображаются на форме. Именно поэтому не нужно «возвращать» строку обратно в табличную часть.

Для обращения к конкретной строке по индексу используйте квадратные скобки: ПерваяСтрока = Объект.Товары[0];. Индексация начинается с нуля, а номер строки (свойство НомерСтроки) — с единицы. Это расхождение регулярно становится источником ошибок на одну позицию.

Получение текущей (выделенной) строки

Когда код вызывается из обработчика события таблицы — например, ПриИзменении колонки «Количество» — обычно нужна именно та строка, которую редактирует пользователь. На клиенте её получают так:

&НаКлиенте

Процедура ТоварыКоличествоПриИзменении(Элемент)

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

Возврат;

КонецЕсли;

ТекущиеДанные.Сумма = ТекущиеДанные.Количество * ТекущиеДанные.Цена;

КонецПроцедуры

Проверка на Неопределено обязательна: если таблица пуста или фокус снят, ТекущиеДанные вернёт именно это значение, и обращение к реквизиту вызовет ошибку выполнения.

Объект ТекущиеДанные имеет тип ДанныеФормыЭлементКоллекции. Он позволяет читать и менять реквизиты строки, но у него нет части методов «настоящей» строки табличной части. Если нужна полноценная строка объекта, получите её по идентификатору: СтрокаОбъекта = Объект.Товары.НайтиПоИдентификатору(Элементы.Товары.ТекущаяСтрока);.

Добавление, изменение и удаление строк программно

Добавить строку можно методом Добавить() коллекции. Новая строка сразу появляется на форме, но фокус в неё автоматически не переходит — при необходимости активизируйте её через элемент формы:

НоваяСтрока = Объект.Товары.Добавить();

НоваяСтрока.Номенклатура = ВыбраннаяНоменклатура;

НоваяСтрока.Количество = 1;

Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();

Удаление выполняется методом Удалить() с передачей строки или индекса. При удалении в цикле есть подвох: коллекция сжимается, и индексы смещаются. Безопасный приём — идти с конца или собирать строки к удалению в отдельный массив, а потом удалять:

КоличествоСтрок = Объект.Товары.Количество();

Для Индекс = 1 По КоличествоСтрок Цикл

СтрокаТовара = Объект.Товары[КоличествоСтрок - Индекс];

Если СтрокаТовара.Количество = 0 Тогда

Объект.Товары.Удалить(СтрокаТовара);

КонецЕсли;

КонецЦикла;

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

Работа с табличной частью в серверных процедурах

В процедурах с директивой &НаСервере реквизит Объект остаётся доступным, если у процедуры есть контекст формы. Однако для вызова методов объекта документа (например, типовых процедур заполнения) данные формы нужно преобразовать в прикладной объект:

&НаСервере

Процедура ЗаполнитьПоОстаткамНаСервере()

ДокументОбъект = РеквизитФормыВЗначение("Объект");

ДокументОбъект.Товары.Очистить();

// ... заполнение табличной части

ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

КонецПроцедуры

Критично не забыть обратное преобразование ЗначениеВРеквизитФормы — без него все изменения останутся в локальной переменной и на форме не отобразятся. Это одна из самых коварных ошибок: код выполняется без сообщений об ошибках, а результат «пропадает».

Если серверная процедура объявлена с директивой &НаСервереБезКонтекста, то ни Объект, ни Элементы в ней недоступны. Такие процедуры быстрее вызываются, но в них нужно передавать данные параметрами — например, массив структур со строками табличной части.

Особенности обычных форм

В обычных формах (режим совместимости, старые конфигурации) модель проще: разделения на данные формы и объект нет, табличная часть доступна напрямую как Товары или через ЭтотОбъект.Товары в модуле формы. Текущая строка получается через ЭлементыФормы.Товары.ТекущиеДанные.

Циклы, добавление и удаление строк работают аналогично управляемым формам. Главное отличие — отсутствие клиент-серверных директив: весь код формы выполняется на клиенте (в толстом клиенте) или на сервере (в тонком), и преобразования РеквизитФормыВЗначение не требуются.

Если вы сопровождаете старую конфигурацию на обычных формах, помните: переносить примеры кода из управляемых форм «как есть» нельзя — имена коллекций (Элементы вместо ЭлементыФормы) и модель данных отличаются.

Типичные ошибки и как их проверить

Первая группа ошибок — контекстные: обращение к Элементы на сервере без контекста, к ТекущиеДанные в серверной процедуре, к Объект в модуле команды без параметров. Диагностируются они сообщением «Переменная не определена» или «Поле объекта не обнаружено».

Вторая группа — логические: изменение копии вместо строки, потеря изменений из-за пропущенного ЗначениеВРеквизитФормы, сбой индексов при удалении в прямом цикле, путаница между индексом (с нуля) и номером строки (с единицы).

Типичные ошибки
01
Обращение к реквизиту ТекущиеДанные без проверки на Неопределено — падение при пустой таблице
02
Удаление строк в прямом цикле по индексу — пропуск строк из-за смещения коллекции
03
Забытое ЗначениеВРеквизитФормы после РеквизитФормыВЗначение — изменения не видны на форме
04
Использование Объект.Товары.Найти() вместо НайтиПоИдентификатору для текущей строки — находится не та строка
05
Серверный вызов на каждую строку — резкое падение производительности формы
Контрольные точки

Как проверить результат

Отображение изменений на форме
Норма

После выполнения кода строки таблицы обновились визуально

Тревожный признак

Код отработал без ошибок, но таблица не изменилась — вероятно, изменена копия данных

Модифицированность формы
Норма

В заголовке формы появился признак изменения (звёздочка), документ предлагает записать

Тревожный признак

Форма закрывается без вопроса о записи — изменения потеряны

Текущая строка
Норма

ТекущиеДанные содержит заполненные реквизиты редактируемой строки

Тревожный признак

ТекущиеДанные = Неопределено или данные другой строки

Частые вопросы

Как обратиться к табличной части из модуля объекта, а не формы?

В модуле объекта табличная часть доступна напрямую по имени: Товары или ЭтотОбъект.Товары. Никаких промежуточных реквизитов формы там нет — работа идёт сразу с данными объекта.

Как найти строку по значению реквизита?

Используйте метод НайтиСтроки с структурой отбора: НайденныеСтроки = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", ИскомоеЗначение));. Метод возвращает массив всех подходящих строк, а не одну.

Почему изменения в цикле по Товары не сохраняются при записи?

Чаще всего код выполнялся над копией данных, полученной через РеквизитФормыВЗначение, без обратного преобразования. Реже — строка была скопирована в структуру, и менялась структура, а не строка коллекции.

Можно ли обратиться к табличной части другого документа с формы?

Напрямую через форму — нет. Нужно получить объект другого документа на сервере через Документы.ИмяДокумента.НайтиПоНомеру() или по ссылке (Ссылка.ПолучитьОбъект()) и работать с его табличной частью там.

Как получить итог по колонке табличной части?

Используйте метод Итог: ВсегоСумма = Объект.Товары.Итог("Сумма");. Это быстрее и надёжнее ручного суммирования в цикле и автоматически учитывает все строки.

Чем отличается ТекущаяСтрока от ТекущиеДанные?

ТекущаяСтрока — это числовой идентификатор строки в данных формы, пригодный для НайтиПоИдентификатору. ТекущиеДанные — готовый объект со значениями реквизитов строки, доступный только на клиенте.

Итог

Что важно запомнить

Данные табличной части читайте и меняйте через Объект.ИмяТабличнойЧасти, состояние интерфейса — через Элементы.ИмяТабличнойЧасти. Всегда проверяйте ТекущиеДанные на Неопределено, удаляйте строки в обратном порядке и не забывайте ЗначениеВРеквизитФормы после серверной обработки объекта.