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