Как исправить ошибку: Текущие данные таблицы недоступны на сервере в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Комплексная автоматизация Управленческий учет IT и автоматизация бизнеса
← На главную

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

Почему возникает ошибка доступа к ТекущиеДанные на сервере?

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

Способ 1: Использование идентификатора текущей строки

Самый простой и правильный способ получить доступ к данным строки на сервере — это передать её уникальный Идентификатор. Важно не путать индекс строки (ее порядковый номер) и идентификатор. Индекс может измениться при сортировке, а идентификатор остается неизменным в течение сеанса работы с формой. Разберем по шагам, как это реализовать:

  1. На клиенте получаем идентификатор активной строки через свойство ТекущаяСтрока.
  2. Передаем этот идентификатор в процедуру или функцию &НаСервере.
  3. На сервере находим строку в данных объекта, используя метод НайтиПоИдентификатору().

Рассмотрим пример кода:


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

&НаСервере
Процедура ОбработатьСтрокуНаСервере(ИдентификаторСтроки)
    // Находим строку в табличной части объекта
    ТекущаяСтрокаДанных = Объект.Работы.НайтиПоИдентификатору(ИдентификаторСтроки);
    
    Если ТекущаяСтрокаДанных <> Неопределено Тогда
        // Теперь мы можем работать с реквизитами строки
        ТекущаяСтрокаДанных.Организация = ТекущаяСтрокаДанных.ДоговорКонтрагента.Организация;
    КонецЕсли;
КонецПроцедуры

Способ 2: Оптимизированный вызов без контекста формы

Проанализируем ситуацию, когда нам нужно просто получить данные из справочника (например, основной договор контрагента). В этом случае использование &НаСервере с передачей всей формы избыточно. Лучше использовать &НаСервереБезКонтекста. Это значительно ускоряет работу программы, так как на сервер передается только ссылка на объект, а не вся форма целиком.

Посмотрим на пример реализации через структуру:


&НаСервереБезКонтекста
Функция ПолучитьДанныеКонтрагента(СсылкаКонтрагент)
    Результат = Новый Структура("Договор, Организация");
    
    // Получаем данные напрямую из справочника
    Результат.Договор = СсылкаКонтрагент.ОсновнойДоговорКонтрагента;
    Результат.Организация = СсылкаКонтрагент.ОсновнойДоговорКонтрагента.Организация;
    
    Возврат Результат;
КонецФункции

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

Способ 3: Использование запроса для поиска данных

Иногда требуется подобрать данные по сложным условиям, например, найти договор определенного типа. В таких случаях внутри серверной функции удобно использовать запрос. Выясним, как передать результат запроса обратно на клиент. Напрямую РезультатЗапроса или Выборка на клиент не передаются, поэтому мы будем использовать массив или структуру.


&НаСервереБезКонтекста
Функция НайтиПодходящийДоговор(Контрагент)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    ДоговорыКонтрагентов.Ссылка КАК Договор
        |ИЗ
        |    Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
        |ГДЕ
        |    ДоговорыКонтрагентов.Контрагент = &Контрагент
        |    И ДоговорыКонтрагентов.франТипДоговораФранчайзи = &Тип";
    
    Запрос.УстановитьПараметр("Контрагент", Контрагент);
    Запрос.УстановитьПараметр("Тип", ПредопределенноеЗначение("Перечисление.франТипыДоговоров.Сопровождение"));
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Договор;
    КонецЕсли;
    
    Возврат Справочники.ДоговорыКонтрагентов.ПустаяСсылка();
КонецФункции

Автоматический расчет суммы и итогов

Разберем еще один важный аспект: расчет производных полей, таких как Сумма. Начинающие разработчики часто пытаются отправить данные на сервер, чтобы умножить цену на количество. Это архитектурная ошибка. Все арифметические операции внутри одной строки должны выполняться строго &НаКлиенте. Для удобного вывода суммовых показателей с учетом отборов подойдут готовые процедуры для расчета итогов в подвале табличных частей.

Рассмотрим правильный алгоритм:

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

&НаКлиенте
Процедура ДополнительныеПокупкиКоличествоПриИзменении(Элемент)
    Строка = Элементы.ДополнительныеПокупки.ТекущиеДанные;
    Если Строка <> Неопределено Тогда
        // Простой расчет на клиенте без вызова сервера
        Строка.Сумма = Строка.Количество * Строка.Цена;
    КонецЕсли;
    
    // Если нужно пересчитать итог по всему документу, 
    // можно вызвать серверный метод или посчитать в цикле на клиенте
КонецПроцедуры

Практические советы по оптимизации

Проанализируем работу в крупных конфигурациях, таких как Комплексная автоматизация 2 или ERP. В них часто используется Библиотека стандартных подсистем (БСП). Вместо написания своих функций для получения реквизитов, рекомендуется использовать готовые инструменты:

Для получения одного значения используйте: ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИмяРеквизита").

Для получения нескольких значений: ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "Реквизит1, Реквизит2").

Важный момент: если ваша задача — просто подставить цену товара при его выборе, лучше всего организовать это через &НаСервереБезКонтекста, возвращая структуру данных. Это обеспечит максимальную отзывчивость интерфейса, пользователь даже не заметит задержки при выборе позиции из списка.

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

← На главную