Разработка и Конфигурация · 10 мин
1С: как получить текущую строку табличной части на сервере
Как получить текущую строку табличной части на сервере в 1С: передача данных с клиента, методы НайтиПоИдентификатору, ТекущиеДанные, типовые ошибки и примеры кода.
Задача получить текущую строку табличной части на сервере возникает в управляемых формах 1С постоянно: нужно пересчитать суммы, подобрать цену, проверить остатки или заполнить связанные реквизиты именно для той строки, которую сейчас редактирует пользователь. Сложность в том, что на сервере нет понятия «текущая строка» — контекст формы, выделение и активная строка существуют только на клиенте.
Поэтому правильный подход — не искать «текущую строку» на сервере, а передать туда идентификатор или данные строки с клиента и уже на сервере найти соответствующую строку в данных формы. Способ передачи зависит от того, где лежит табличная часть: в реквизите формы типа «ДанныеФормыКоллекция» или в объекте (например, в табличной части документа, доступной через Объект.Товары).
Ниже разобраны рабочие варианты для обоих случаев, типовые ошибки вроде передачи всей коллекции на сервер и ограничения контекстных серверных вызовов. Примеры ориентированы на управляемые формы платформы 8.3.
Почему на сервере нет текущей строки
В управляемой форме клиент и сервер — два разных контекста исполнения. Таблица формы, её текущая строка, выделение и свойства элемента формы существуют только на тонком или веб-клиенте. Серверный код работает с данными формы (ДанныеФормыКоллекция, ДанныеФормыСтруктура), но понятия «активная строка» у этих данных нет.
Именно поэтому попытка написать в серверной процедуре что-то вроде Элементы.Товары.ТекущаяСтрока закончится ошибкой: коллекция Элементы и свойство ТекущаяСтрока недоступны в серверном контексте. Компилятор модуля формы это не всегда отловит заранее, поэтому ошибка часто всплывает только в момент выполнения.
Правильная схема всегда одна: клиент определяет текущую строку, извлекает из неё идентификатор или значения полей и передаёт их параметром в серверную процедуру. Сервер по этим данным находит строку в своём представлении коллекции и выполняет нужную логику.
Способ 1: передать идентификатор строки и найти её на сервере
Самый распространённый и надёжный вариант — передать идентификатор текущей строки. На клиенте он доступен как Элементы.Товары.ТекущаяСтрока (для табличной части объекта это и есть идентификатор строки данных формы). На сервере строка ищется методом НайтиПоИдентификатор().
&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
ИдентификаторСтроки = Элементы.Товары.ТекущаяСтрока;
ПересчитатьСтрокуНаСервере(ИдентификаторСтроки);
КонецПроцедуры
&НаСервере
Процедура ПересчитатьСтрокуНаСервере(ИдентификаторСтроки)
СтрокаТаблицы = Объект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);
Если СтрокаТаблицы = Неопределено Тогда
Возврат;
КонецЕсли;
СтрокаТаблицы.Сумма = СтрокаТаблицы.Количество * СтрокаТаблицы.Цена;
КонецПроцедурыКлючевые моменты этого подхода. Во-первых, НайтиПоИдентификатору() работает и для табличной части объекта (Объект.Товары), и для реквизита формы типа ДанныеФормыКоллекция — сигнатура одинаковая. Во-вторых, изменения, внесённые в строку на сервере, автоматически отобразятся в форме, потому что меняются данные формы, а не их копия.
Обязательно проверяйте результат поиска на Неопределено. Если строка была удалена между клиентским событием и серверным вызовом (редко, но возможно при сложной логике), обращение к полям несуществующей строки вызовет ошибку.
Способ 2: передать данные строки структурой
Если серверной логике нужны только значения полей строки, а саму строку в данных формы менять не требуется, можно передать структуру с нужными полями. Это удобно для расчётов «на стороне»: подбор цены из регистра, проверка остатка, получение ставки НДС.
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
ДанныеСтроки = Новый Структура("Номенклатура,Количество");
ЗаполнитьЗначенияСвойств(ДанныеСтроки, ТекущиеДанные);
ТекущиеДанные.Цена = ПолучитьЦенуНаСервере(ДанныеСтроки, Объект.Дата);
КонецПроцедурыТакой вариант уменьшает связанность кода: серверная процедура не зависит от структуры табличной части и легко тестируется. Но помните, что структура — это копия значений. Изменения в ней на сервере обратно в строку не попадут: результат нужно вернуть и присвоить на клиенте, как в примере выше.
Комбинированный вариант — передать и идентификатор, и структуру — оправдан, когда сервер должен и прочитать дополнительные данные по полям строки, и записать результат в несколько реквизитов той же строки.
Способ 3: контекстный серверный вызов без передачи строки
Если серверная процедура объявлена с директивой &НаСервере (а не &НаСервереБезКонтекста), в ней доступны все данные формы, включая Объект и реквизиты-таблицы. Но «текущей строки» там всё равно нет — контекст формы переносит данные, а не состояние интерфейса. Идентификатор строки передать всё равно придётся.
Отдельный случай — обработчики событий самой таблицы, вызываемые на сервере, например ТоварыПриОкончанииРедактирования с серверным вызовом или обработка заполнения объекта. В модуле объекта (ПриЗаполнении, ОбработкаПроведения) табличная часть доступна напрямую как коллекция строк, и там понятие «текущая строка» заменяется явным перебором через Для Каждого СтрокаТаблицы Из Товары Цикл.
Сравнение вариантов
Универсальный вариант: сервер меняет саму строку данных формы. Подходит почти всегда, требует проверки на Неопределено.
Подходит для расчётов без изменения строки. Результат нужно вернуть и присвоить на клиенте.
Для проведения и заполнения, когда обрабатываются все строки, а не одна текущая.
Типичные ошибки и как их избежать
Самая частая ошибка — попытка передать на сервер объект ТекущиеДанные целиком. Данные текущей строки на клиенте имеют тип, не сериализуемый между клиентом и сервером, и вызов завершится ошибкой преобразования данных. Передавать нужно либо идентификатор, либо структуру с примитивными значениями и ссылками.
Вторая ошибка — использовать &НаСервереБезКонтекста и при этом пытаться обратиться к Объект.Товары. В процедуре без контекста данных формы нет: туда нужно либо передавать ссылку на объект и читать его заново (что долго и опасно при несохранённых изменениях), либо менять директиву на &НаСервере.
Третья группа ошибок — лишние серверные вызовы. Если обработчик «ПриИзменении» срабатывает на каждое редактирование ячейки, а внутри — серверный вызов, форма начнёт заметно тормозить. Простую арифметику (Сумма = Количество × Цена) лучше считать на клиенте, а на сервер выносить только то, что требует запросов к базе.
Как проверить, что всё работает правильно
После внедрения кода проверьте три сценария. Первый: редактирование существующей строки — изменения должны появиться в таблице сразу после серверного вызова, без перечитывания формы. Второй: добавление новой строки — идентификатор у новой строки уже существует на клиенте, и НайтиПоИдентификатору должен её находить. Третий: быстрое последовательное редактирование нескольких строк — каждый вызов должен обрабатывать именно свою строку, а не последнюю активную.
Для отладки удобно временно выводить идентификатор строки через Сообщить() на клиенте и на сервере и сравнивать значения — они должны совпадать. Если на сервере поиск возвращает Неопределено при корректном идентификаторе, проверьте, не ищете ли вы строку в другой коллекции (например, в реквизите формы вместо табличной части объекта).
Как проверить результат
НайтиПоИдентификатору возвращает строку, поля доступны
Возвращается Неопределено — неверный идентификатор или не та коллекция
После серверного вызова значения в таблице формы обновились
Значения не меняются — изменена копия, а не данные формы
Идентификатор новой строки находится на сервере
Новая строка не находится — проверьте момент вызова обработчика
FAQ
Можно ли получить текущую строку табличной части в &НаСервереБезКонтекста?
Напрямую — нет, потому что в такой процедуре нет данных формы. Варианты: передать идентификатор строки и ссылку на объект, затем прочитать объект из базы (но вы получите сохранённые данные, а не редактируемые), либо сменить директиву на &НаСервере и работать с данными формы.
Чем ТекущаяСтрока отличается от ТекущиеДанные?
ТекущаяСтрока — это идентификатор (число) активной строки таблицы формы. ТекущиеДанные — объект со значениями полей этой строки. Для передачи на сервер годится только идентификатор; ТекущиеДанные сериализовать нельзя, из него нужно скопировать поля в структуру.
Работает ли НайтиПоИдентификатору для динамического списка?
Для динамических списков метод НайтиПоИдентификатору не применяется — там ТекущаяСтрока содержит ключ записи (обычно ссылку). Если список построен по регистру, ключ может быть структурой записи. Для табличных частей и реквизитов-таблиц метод работает штатно.
Как обработать выделенные строки, а не одну текущую?
Используйте Элементы.Товары.ВыделенныеСтроки — это массив идентификаторов. Передайте его на сервер и в цикле найдите каждую строку через НайтиПоИдентификатору. Массивы примитивных значений между клиентом и сервером передаются без ограничений.
Нужно ли пересчитывать сумму строки на сервере?
Если расчёт — простая арифметика по полям строки, делайте его на клиенте: это мгновенно и не грузит соединение. На сервер выносите только то, что требует запросов к базе: получение цен, остатков, скидок, проверку лимитов.
Почему изменения строки на сервере не видны в форме?
Чаще всего потому, что изменена копия данных: например, строка получена через ДанныеФормыВЗначение и обратно не возвращена, либо менялась структура, а не строка данных формы. Работайте напрямую со строкой, найденной через НайтиПоИдентификатору в реквизите формы.
Что важно запомнить
Текущая строка существует только на клиенте. На сервер передавайте идентификатор строки и находите её через НайтиПоИдентификатору с проверкой на Неопределено. Для расчётов без изменения строки передавайте структуру полей. Не передавайте ТекущиеДанные целиком и не вызывайте сервер на каждое изменение ячейки без необходимости.