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

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

1С: как получить текущую строку табличной части на сервере

Как получить текущую строку табличной части на сервере в 1С: передача данных с клиента, методы НайтиПоИдентификатору, ТекущиеДанные, типовые ошибки и примеры кода.

Задача получить текущую строку табличной части на сервере возникает в управляемых формах 1С постоянно: нужно пересчитать суммы, подобрать цену, проверить остатки или заполнить связанные реквизиты именно для той строки, которую сейчас редактирует пользователь. Сложность в том, что на сервере нет понятия «текущая строка» — контекст формы, выделение и активная строка существуют только на клиенте.

Поэтому правильный подход — не искать «текущую строку» на сервере, а передать туда идентификатор или данные строки с клиента и уже на сервере найти соответствующую строку в данных формы. Способ передачи зависит от того, где лежит табличная часть: в реквизите формы типа «ДанныеФормыКоллекция» или в объекте (например, в табличной части документа, доступной через Объект.Товары).

Ниже разобраны рабочие варианты для обоих случаев, типовые ошибки вроде передачи всей коллекции на сервер и ограничения контекстных серверных вызовов. Примеры ориентированы на управляемые формы платформы 8.3.

Почему на сервере нет текущей строки

В управляемой форме клиент и сервер — два разных контекста исполнения. Таблица формы, её текущая строка, выделение и свойства элемента формы существуют только на тонком или веб-клиенте. Серверный код работает с данными формы (ДанныеФормыКоллекция, ДанныеФормыСтруктура), но понятия «активная строка» у этих данных нет.

Именно поэтому попытка написать в серверной процедуре что-то вроде Элементы.Товары.ТекущаяСтрока закончится ошибкой: коллекция Элементы и свойство ТекущаяСтрока недоступны в серверном контексте. Компилятор модуля формы это не всегда отловит заранее, поэтому ошибка часто всплывает только в момент выполнения.

Правильная схема всегда одна: клиент определяет текущую строку, извлекает из неё идентификатор или значения полей и передаёт их параметром в серверную процедуру. Сервер по этим данным находит строку в своём представлении коллекции и выполняет нужную логику.

Способ 1: передать идентификатор строки и найти её на сервере

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

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

&НаСервере
Процедура ПересчитатьСтрокуНаСервере(ИдентификаторСтроки)
    СтрокаТаблицы = Объект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);
    Если СтрокаТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;
    СтрокаТаблицы.Сумма = СтрокаТаблицы.Количество * СтрокаТаблицы.Цена;
КонецПроцедуры

Ключевые моменты этого подхода. Во-первых, НайтиПоИдентификатору() работает и для табличной части объекта (Объект.Товары), и для реквизита формы типа ДанныеФормыКоллекция — сигнатура одинаковая. Во-вторых, изменения, внесённые в строку на сервере, автоматически отобразятся в форме, потому что меняются данные формы, а не их копия.

Обязательно проверяйте результат поиска на Неопределено. Если строка была удалена между клиентским событием и серверным вызовом (редко, но возможно при сложной логике), обращение к полям несуществующей строки вызовет ошибку.

Способ 2: передать данные строки структурой

Если серверной логике нужны только значения полей строки, а саму строку в данных формы менять не требуется, можно передать структуру с нужными полями. Это удобно для расчётов «на стороне»: подбор цены из регистра, проверка остатка, получение ставки НДС.

bsl
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    ДанныеСтроки = Новый Структура("Номенклатура,Количество");
    ЗаполнитьЗначенияСвойств(ДанныеСтроки, ТекущиеДанные);
    ТекущиеДанные.Цена = ПолучитьЦенуНаСервере(ДанныеСтроки, Объект.Дата);
КонецПроцедуры

Такой вариант уменьшает связанность кода: серверная процедура не зависит от структуры табличной части и легко тестируется. Но помните, что структура — это копия значений. Изменения в ней на сервере обратно в строку не попадут: результат нужно вернуть и присвоить на клиенте, как в примере выше.

Комбинированный вариант — передать и идентификатор, и структуру — оправдан, когда сервер должен и прочитать дополнительные данные по полям строки, и записать результат в несколько реквизитов той же строки.

Способ 3: контекстный серверный вызов без передачи строки

Если серверная процедура объявлена с директивой &НаСервере (а не &НаСервереБезКонтекста), в ней доступны все данные формы, включая Объект и реквизиты-таблицы. Но «текущей строки» там всё равно нет — контекст формы переносит данные, а не состояние интерфейса. Идентификатор строки передать всё равно придётся.

Отдельный случай — обработчики событий самой таблицы, вызываемые на сервере, например ТоварыПриОкончанииРедактирования с серверным вызовом или обработка заполнения объекта. В модуле объекта (ПриЗаполнении, ОбработкаПроведения) табличная часть доступна напрямую как коллекция строк, и там понятие «текущая строка» заменяется явным перебором через Для Каждого СтрокаТаблицы Из Товары Цикл.

Сравнение вариантов

Идентификатор + НайтиПоИдентификатору

Универсальный вариант: сервер меняет саму строку данных формы. Подходит почти всегда, требует проверки на Неопределено.

Структура с полями строки

Подходит для расчётов без изменения строки. Результат нужно вернуть и присвоить на клиенте.

Перебор в модуле объекта

Для проведения и заполнения, когда обрабатываются все строки, а не одна текущая.

Типичные ошибки и как их избежать

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

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

Третья группа ошибок — лишние серверные вызовы. Если обработчик «ПриИзменении» срабатывает на каждое редактирование ячейки, а внутри — серверный вызов, форма начнёт заметно тормозить. Простую арифметику (Сумма = Количество × Цена) лучше считать на клиенте, а на сервер выносить только то, что требует запросов к базе.

Типичные ошибки
01
Передача ТекущиеДанные на сервер целиком — ошибка сериализации, передавайте идентификатор или структуру
02
Обращение к Элементы.Товары.ТекущаяСтрока в серверной процедуре — элементы формы недоступны на сервере
03
Отсутствие проверки результата НайтиПоИдентификатору на Неопределено — ошибка при обращении к полям
04
Серверный вызов на каждое изменение ячейки — лишняя нагрузка и тормоза формы
05
Использование &НаСервереБезКонтекста при необходимости работать с данными формы

Как проверить, что всё работает правильно

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

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

Контрольные точки

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

Поиск строки на сервере
Норма

НайтиПоИдентификатору возвращает строку, поля доступны

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

Возвращается Неопределено — неверный идентификатор или не та коллекция

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

После серверного вызова значения в таблице формы обновились

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

Значения не меняются — изменена копия, а не данные формы

Новая строка
Норма

Идентификатор новой строки находится на сервере

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

Новая строка не находится — проверьте момент вызова обработчика

FAQ

Можно ли получить текущую строку табличной части в &НаСервереБезКонтекста?

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

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

ТекущаяСтрока — это идентификатор (число) активной строки таблицы формы. ТекущиеДанные — объект со значениями полей этой строки. Для передачи на сервер годится только идентификатор; ТекущиеДанные сериализовать нельзя, из него нужно скопировать поля в структуру.

Работает ли НайтиПоИдентификатору для динамического списка?

Для динамических списков метод НайтиПоИдентификатору не применяется — там ТекущаяСтрока содержит ключ записи (обычно ссылку). Если список построен по регистру, ключ может быть структурой записи. Для табличных частей и реквизитов-таблиц метод работает штатно.

Как обработать выделенные строки, а не одну текущую?

Используйте Элементы.Товары.ВыделенныеСтроки — это массив идентификаторов. Передайте его на сервер и в цикле найдите каждую строку через НайтиПоИдентификатору. Массивы примитивных значений между клиентом и сервером передаются без ограничений.

Нужно ли пересчитывать сумму строки на сервере?

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

Почему изменения строки на сервере не видны в форме?

Чаще всего потому, что изменена копия данных: например, строка получена через ДанныеФормыВЗначение и обратно не возвращена, либо менялась структура, а не строка данных формы. Работайте напрямую со строкой, найденной через НайтиПоИдентификатору в реквизите формы.

Итог

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

Текущая строка существует только на клиенте. На сервер передавайте идентификатор строки и находите её через НайтиПоИдентификатору с проверкой на Неопределено. Для расчётов без изменения строки передавайте структуру полей. Не передавайте ТекущиеДанные целиком и не вызывайте сервер на каждое изменение ячейки без необходимости.