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