Как правильно реализовать добавление и отображение картинок в веб-клиенте 1С

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

При разработке интерфейсов в веб-клиенте программисты часто сталкиваются с проблемой: при попытке загрузить картинку в табличную часть объекта (например, справочника «Номенклатура»), данные внезапно «исчезают» (принимают значение Неопределено) сразу после выполнения преобразования ЗначениеВРеквизитФормы. Это происходит из-за особенностей работы управляемых форм и механизмов сериализации данных.

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

Почему данные пропадают: корень проблемы

Основная причина, по которой после выполнения кода ЗначениеВРеквизитФормы(НоменклатураОбъект, "Объект") поле с картинкой очищается, кроется в несовместимости типов. Объект платформы ХранилищеЗначения предназначен исключительно для работы на стороне сервера и хранения данных непосредственно в базе (в реквизитах объектов). Однако реквизиты формы (структуры типа ДанныеФормыСтруктура или коллекции ДанныеФормыКоллекция) не поддерживают этот тип данных.

Когда вы выполняете преобразование «Объект -> Реквизит формы», платформа пытается сопоставить поля. Поскольку в реквизитах формы нет типа, эквивалентного ХранилищеЗначения, данные просто игнорируются или сбрасываются. В веб-клиенте эта ситуация усугубляется строгими правилами передачи данных между браузером и сервером.

Решение №1: Использование временных адресов (метод «Адресной колонки»)

Проанализируем наиболее эффективный способ работы в рамках формы. Вместо того чтобы пытаться сразу поместить двоичные данные в реквизит объекта, мы будем использовать адрес временного хранилища. Рассмотрим этот алгоритм по шагам.

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

Шаг 2. Загрузка файла. Используем асинхронные методы для помещения файла на сервер. Посмотрим на пример кода:


&НаКлиенте
Асинх Процедура ВыбратьКартинку(Команда)
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Картинки (*.jpg;*.png)|*.jpg;*.png";
    
    Результат = Ждать ПоместитьФайлыНаСерверАсинх(,,, Диалог, УникальныйИдентификатор);
    
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Для каждого Файл Из Результат Цикл
        ДобавитьСтрокуСКартинкой(Файл.Адрес, Файл.Файл.Имя);
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Обработка на сервере. Здесь мы не трогаем СправочникОбъект раньше времени. Мы просто добавляем данные в коллекцию формы:


&НаСервере
Процедура ДобавитьСтрокуСКартинкой(Адрес, ИмяФайла)
    НоваяСтрока = Объект.ВебКартинки.Добавить();
    НоваяСтрока.ИмяФайла = ИмяФайла;
    // Сохраняем только временный адрес!
    НоваяСтрока.АдресКартинки = Адрес; 
КонецПроцедуры

Шаг 4. Отображение. Чтобы пользователь видел картинку в интерфейсе, в элементе формы «Поле картинки» (которое находится внутри таблицы или отдельно) в свойстве ПутьКДанным укажем Объект.ВебКартинки.ТекущиеДанные.АдресКартинки. Платформа 1С сама подтянет изображение из временного хранилища по этой ссылке.

Решение №2: Архитектурно правильное хранение файлов

Как справедливо отмечают эксперты, хранить бинарные данные (картинки) в табличной части основного справочника — это плохая практика. Если у вас будет 10 000 товаров, и у каждого по 3–5 тяжелых фото в ТЧ, справочник Номенклатура станет весить гигабайты. Это приведет к критическому замедлению работы при любом поиске или открытии списка.

Разберем канонический подход (используемый в БСП):

  1. Создаем отдельный справочник НоменклатураПрисоединенныеФайлы.
  2. В этом справочнике создаем реквизит Файл с типом ХранилищеЗначения.
  3. В основной табличной части Номенклатуры храним только Ссылку на этот новый справочник.

Это позволит основной таблице оставаться «легкой», а данные файлов будут подгружаться только тогда, когда они действительно нужны.

Сохранение данных: обработчик ПередЗаписьюНаСервере

Выясним, как окончательно зафиксировать картинки в базе данных. Лучшее место для этого — системное событие ПередЗаписьюНаСервере. В этот момент у нас есть доступ и к данным формы (Объект), и к самому записываемому объекту базы данных (ТекущийОбъект).

Проанализируем пример реализации:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    Для каждого СтрокаТЧ Из Объект.ВебКартинки Цикл
        
        // Проверяем, является ли адрес ссылкой на временное хранилище
        Если ЭтоАдресВременногоХранилища(СтрокаТЧ.АдресКартинки) Тогда
            
            ДвоичныеДанные = ПолучитьИзВременногоХранилища(СтрокаТЧ.АдресКартинки);
            
            // Находим соответствующую строку в записываемом объекте
            // (используем индекс или идентификатор строки)
            Индекс = Объект.ВебКартинки.Индекс(СтрокаТЧ);
            СтрокаОбъекта = ТекущийОбъект.ВебКартинки[Индекс];
            
            // Вот здесь мы работаем с ХранилищемЗначения в Объекте БД
            СтрокаОбъекта.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанные);
            
            // Удаляем из временного хранилища, чтобы не забивать память
            УдалитьИзВременногоХранилища(СтрокаТЧ.АдресКартинки);
            
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важные нюансы работы в Веб-клиенте

Рассмотрим специфику, которую необходимо учитывать при работе через браузер:

1. Навигационные ссылки: Метод ПолучитьНавигационнуюСсылку(Объект.Ссылка, ...) не будет работать для новых объектов, которые еще не записаны в базу. Именно поэтому использование временных адресов (e1cib/tempstorage/...) является единственным надежным способом отображения фото до нажатия кнопки «Записать».

2. Интерактивность: Браузеры блокируют программное открытие файлов. Поэтому вызов ПоместитьФайлыНаСервер всегда должен быть инициирован непосредственным действием пользователя (нажатием кнопки).

3. Уникальный идентификатор: Всегда передавайте УникальныйИдентификатор формы в методы помещения файлов. Это гарантирует, что временное хранилище будет «привязано» к текущей форме и не очистится преждевременно при серверном вызове.

Итоги

Мы проанализировали ситуацию и выяснили, что прямой перенос данных типа ХранилищеЗначения в реквизиты формы невозможен. Для корректной работы в веб-клиенте следует использовать комбинированный подход: хранить временные адреса строк в экранных реквизитах для визуализации и преобразовывать их в двоичные данные только в момент записи объекта на сервере. Также крайне рекомендуется рассмотреть вынос медиа-данных в отдельные справочники, чтобы обеспечить высокую производительность системы в будущем.

← На главную