При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда код, идеально работающий в тонком клиенте, ведет себя непредсказуемо в веб-клиенте. Одной из таких классических проблем является работа с объектом ТабличныйДокумент. Рассмотрим ситуацию: у нас есть сформированный документ, который мы пытаемся вывести пользователю на форму, но вместо заполненных данных в браузере видим пустой лист, хотя в тонком клиенте всё отображается корректно. Разберем по шагам, почему это происходит и как правильно организовать вывод данных.
Проанализируем исходный алгоритм, который вызывает затруднения. Разработчик пытается выполнить присваивание сформированного документа реквизиту формы непосредственно в клиентской процедуре:
&НаКлиенте
Процедура ОтобразитьДокумент(ТД)
Если ТипЗнч(ТД) = Тип("ТабличныйДокумент") Тогда
#Если ВебКлиент Тогда
// Попытка присвоения в веб-клиенте
ТабличныйДокумент = ТД;
#Иначе
// Попытка присвоения в тонком клиенте
ТабличныйДокумент = ТД;
#КонецЕсли
КонецЕсли;
КонецПроцедуры
В тонком клиенте это работает, так как приложение имеет прямой доступ к памяти и объектам операционной системы. Однако веб-клиент — это, по сути, среда JavaScript внутри браузера. Здесь объект ТабличныйДокумент проходит через процесс сериализации. Когда мы просто присваиваем объект на клиенте, платформа не всегда инициирует полноценное обновление графического интерфейса в браузере. Выясним причину: браузеру недостаточно просто "знать", что переменная изменилась, ему нужно получить сформированный HTML/CSS пакет для отрисовки ячеек, чего при простом клиентском присваивании может не произойти.
Как показывает практика и обсуждение на форуме, самым надежным способом заставить веб-клиент отобразить данные является выполнение присваивания в контексте сервера. Когда управление передается на сервер и реквизит формы заполняется там, при возврате управления на клиент платформа автоматически генерирует необходимый массив данных для визуализации в браузере.
Рассмотрим правильную структуру вызова:
&НаКлиенте
Процедура ВыполнитьВывод()
// Предположим, ТД_Сформированный уже получен
ТДСервер(ТД_Сформированный);
КонецПроцедуры
&НаСервере
Процедура ТДСервер(ТД)
// Реквизит формы "ТабличныйДокумент" заполняется на сервере
ЭтаФорма.ТабличныйДокумент = ТД;
КонецПроцедуры
Этот метод гарантирует результат, но имеет один существенный минус, упомянутый автором вопроса: низкая скорость работы. Это происходит из-за того, что при вызове &НаСервере передается весь контекст формы (все реквизиты, данные и состояние элементов управления), что в веб-клиенте создает большой трафик между браузером и сервером приложений.
Чтобы избежать "тормозов" в веб-клиенте, мы можем минимизировать объем передаваемых данных. Вместо того чтобы гонять весь объект ТабличныйДокумент через параметры клиентских процедур, воспользуемся временным хранилищем. Разберем этот эффективный способ подробнее.
Посмотрим на пример кода:
&НаСервереБезКонтекста
Функция СформироватьТДНаСервере()
ТД = Новый ТабличныйДокумент;
// ... логика заполнения документа ...
Возврат ПоместитьВоВременноеХранилище(ТД, Новый УникальныйИдентификатор);
КонецФункции
&НаСервере
Процедура ЗаполнитьТДИзХранилища(Адрес)
// Получаем объект и присваиваем его реквизиту формы
ТД_ИзХранилища = ПолучитьИзВременногоХранилища(Адрес);
Если ТипЗнч(ТД_ИзХранилища) = Тип("ТабличныйДокумент") Тогда
ЭтаФорма.РезультатТабличныйДокумент = ТД_ИзХранилища;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура КомандаСформировать(Команда)
Адрес = СформироватьТДНаСервере();
ЗаполнитьТДИзХранилища(Адрес);
КонецПроцедуры
Такой подход значительно ускоряет работу в веб-клиенте, так как мы не передаем тяжелый объект ТабличныйДокумент в параметрах вызова, а работаем с короткой строкой-ссылкой.
Иногда проблему обновления визуального состояния в веб-клиенте можно решить без полной перезаписи объекта. Выясним, как работает метод Вывести(). Если у вас уже есть пустой реквизит формы типа ТабличныйДокумент, вместо прямого присваивания можно попробовать использовать метод вывода документа в документ.
Проанализируем ситуацию: метод Вывести() заставляет движок платформы зафиксировать изменения в структуре документа. Хотя это чаще используется для построчного формирования, в случае с веб-клиентом это может послужить "триггером" для обновления DOM-модели в браузере.
&НаСервере
Процедура ВывестиТДНаСервере(ВходящийТД)
ЭтаФорма.РеквизитТабличныйДокумент.Очистить();
ЭтаФорма.РеквизитТабличныйДокумент.Вывести(ВходящийТД);
КонецПроцедуры
Многие разработчики пытаются использовать метод ОбновитьОтображениеДанных(), чтобы "протолкнуть" изменения из памяти на экран. Однако в случае с веб-клиентом и табличным документом это часто оказывается бесполезным. Проблема в том, что ОбновитьОтображениеДанных() обновляет визуальное состояние элементов, связанных с данными, которые уже синхронизированы между клиентом и сервером. Если само присваивание ТабличныйДокумент = ТД на клиенте не привело к синхронизации внутреннего состояния объекта с сервером (что является особенностью веб-клиента), то обновлять визуально просто нечего — платформа "считает", что документ пуст.
Для стабильной и быстрой работы с табличными документами в веб-интерфейсе 1С следует придерживаться следующих правил:
&НаКлиенте, если планируете использовать веб-клиент.&НаСервере).&НаСервереБезКонтекста для формирования данных, а в контекстный серверный вызов передавайте только адрес (строку).Соблюдение этих архитектурных принципов позволит вашим решениям работать одинаково быстро и корректно как в тяжелом приложении, так и в любом современном браузере через веб-клиент.