Как правильно обновить данные в строке табличной части при переходе между клиентом и сервером в 1С 8.3?

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

В разработке на управляемых формах 1С 8.3 одной из самых распространенных преград для новичков становится понимание границ между клиентским и серверным контекстами. Типичная ситуация: при изменении значения в одной колонке табличной части (например, при выборе счетчика) необходимо автоматически подтянуть данные в другие колонки (коэффициент, заводской номер, абонент). Рассмотрим, почему возникают ошибки при попытке вызвать «клиент из сервера», и разберем правильные архитектурные подходы к решению этой задачи.

Разбор основной ошибки: почему сервер «не видит» клиент?

Проанализируем ситуацию, описанную в исходном коде. Автор пытается из серверной процедуры ЗаполнениеТЧНаОсновеВведенныхДанных вызвать клиентскую процедуру ОбновлениеДанныхТЧ. При этом система выдает ошибку: «Процедура или функция с указанным именем не определена». Это происходит потому, что в управляемом приложении 1С реализована строгая иерархия вызовов. Клиент может инициировать серверный вызов, но сервер никогда не может инициировать выполнение кода на клиенте в рамках одного потока выполнения.

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

Решение №1: Использование серверной процедуры с контекстом формы

Этот метод наиболее близок к тому, что пытался реализовать автор. Мы передаем управление на сервер, модифицируем данные непосредственно в Объект.ТЧ..., и после завершения серверной процедуры платформа автоматически синхронизирует измененные данные с интерфейсом пользователя.

Разберем по шагам, как это должно выглядеть:

  1. На клиенте в событии ПриИзменении мы определяем идентификатор текущей строки.
  2. Вызываем серверную процедуру, передавая этот идентификатор.
  3. На сервере находим нужную строку в объекте и заполняем её данными.

Посмотрим на пример правильного кода:


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

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

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

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

Решение №2: Использование внеконтекстного серверного вызова (Оптимальный вариант)

Для повышения производительности, особенно при работе в «тонком клиенте» через интернет, рекомендуется использовать &НаСервереБезКонтекста. В этом случае на сервер не передается вся форма (весь Объект), а только необходимые параметры. Сервер возвращает структуру данных, которую мы применяем к строке на клиенте.

Выясним причину эффективности этого метода: уменьшается объем трафика и нагрузка на память сервера. Рассмотрим реализацию:


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

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

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

КонецФункции

Рекомендации по массовому заполнению табличной части

Если ваша задача — не обновить одну строку, а полностью перезаполнить таблицу (как в процедуре ВыборкаДанных из сообщения автора), проанализируем ситуацию с точки зрения быстродействия. Использование метода Объект.ТЧ.Добавить() в цикле на сервере допустимо, но при большом количестве строк (более 1000) это может замедлить работу интерфейса.

Советы по оптимизации:

Итоги: правила «хорошего тона» в управляемом коде

Чтобы больше не сталкиваться с ошибками определения процедур и недоступностью данных, запомним три правила:

1. Направление вызова: Клиент -> Сервер (Да), Сервер -> Клиент (Нет). Если вам нужно что-то сделать на клиенте после сервера — делайте это в клиентской процедуре после возврата из серверной функции.

2. Доступ к элементам: Элементы и ТекущиеДанные — это только клиент. Если вы на сервере, забудьте про «текущую строку» и работайте либо с конкретным объектом по индексу/идентификатору, либо с переданными параметрами.

3. Разделение логики: Процедуры &НаСервере (с контекстом) используйте только тогда, когда нужно изменить множество реквизитов самого документа или выполнить сложные действия с формой. Для получения справочной информации всегда выбирайте &НаСервереБезКонтекста.

Соблюдение этих принципов сделает ваш код чище, а приложение — быстрее и стабильнее.

← На главную