Как преобразовать данные JSON в таблицу значений, свернуть ее и проверить заполнение реквизитов в 1С 8.3?

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

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

1. Архитектурный барьер: Клиент и Сервер в управляемом приложении

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

Проанализируем некорректный код из обсуждения:


&НаСервере
Функция ВызовКонвертации(Сотрудники)
    ТЗ = ОбщийМодуль.ПреобразоватьМассивВТаблицуЗначений(Сотрудники);
    // Ошибка! Напрямую присвоить ТЗ элементу управляемой формы нельзя
    ЭлементыФормы.ТабличноеПоле1.Значение = ТЗ; 
КонецФункции

Здесь мы видим сразу две критические ошибки:

  1. Конструкция ЭлементыФормы относится к устаревшим Обычным формам. В Управляемых формах используется коллекция Элементы.
  2. Для отображения таблицы значений на управляемой форме ее необходимо связать с реквизитом формы (типа ТаблицаЗначений) через специальный мост-конвертер.

Выясним, как сделать это правильно. Нам потребуется создать реквизит управляемой формы (например, с именем СотрудникиТаблица) и воспользоваться платформенным методом ЗначениеВДанныеФормы() на сервере. Рассмотрим рабочий пример:


&НаСервере
Процедура ЗаполнитьТаблицуНаФорме(МассивСотрудников)
    
    // 1. Создаем физическую таблицу значений на сервере
    ТЗСотрудники = ПреобразоватьМассивВТаблицуЗначений(МассивСотрудников);
    
    // 2. Конвертируем серверный объект ТЗ в реквизит управляемой формы
    ЗначениеВДанныеФормы(ТЗСотрудники, Объект.СотрудникиТаблица);
    
КонецПроцедуры

Благодаря вызову ЗначениеВДанныеФормы(), данные физической таблицы преобразуются в структуру данных формы (тип ДанныеФормыКоллекция), которая прекрасно видна как на сервере, так и на клиенте, и мгновенно визуализируется в интерфейсе пользователя.

2. Чтение JSON и динамическое создание Таблицы Значений

Рассмотрим, как правильно прочитать JSON-структуру и преобразовать ее в таблицу значений с явным указанием типов колонок. Динамическое создание колонок без указания типов — плохая практика, так как в дальнейшем мы не сможем использовать эту таблицу в запросах или корректно агрегировать данные.

Напишем универсальную функцию десериализации JSON и наполнения таблицы значений на сервере:


&НаСервереБезКонтекста
Функция ПреобразоватьМассивВТаблицуЗначений(МассивДанных) Экспорт
    
    ТЗ = Новый ТаблицаЗначений;
    
    Если МассивДанных.Количество() = 0 Тогда
        Возврат ТЗ;
    КонецЕсли;
    
    // Для правильной типизации определим типы колонок заранее
    // Это критически важно для последующей группировки и работы с запросами
    ОписательСтроки = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150));
    ОписательЧисла = Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(10, 0));
    
    ТЗ.Колонки.Добавить("Фамилия", ОписательСтроки);
    ТЗ.Колонки.Добавить("Имя", ОписательСтроки);
    ТЗ.Колонки.Добавить("Отчество", ОписательСтроки);
    ТЗ.Колонки.Добавить("Подразделение", ОписательСтроки);
    ТЗ.Колонки.Добавить("Количество", ОписательЧисла); // Обязательно числовой тип!
    
    Для Каждого ЭлементМассива Из МассивДанных Цикл
        
        НоваяСтрока = ТЗ.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементМассива);
        
        // JSON передает числа в строковом формате. 
        // Приведем значение количества к числу принудительно, чтобы избежать ошибок при сворачивании
        НоваяСтрока.Количество = Число(ЭлементМассива.Количество);
        
    КонецЦикла;
    
    Возврат ТЗ;    
КонецФункции

Обратите внимание на использование функции ЗаполнитьЗначенияСвойств(). Она автоматически сопоставляет ключи структуры из JSON с именами колонок нашей таблицы значений, что избавляет нас от ручного обхода полей в цикле.

3. Группировка данных: Метод "Свернуть" и альтернатива в виде запроса

Рассмотрим ситуацию, когда нам необходимо сгруппировать сотрудников по фамилии и посчитать количество дублей. У нас есть два пути: классический метод Свернуть() и более гибкий механизм запросов 1С.

Вариант А. Использование метода Свернуть()

Метод Свернуть() принимает два параметра-строки: колонки группировки и колонки суммирования. Важно помнить, что все колонки, которые не будут перечислены в этих параметрах, будут безвозвратно удалены из таблицы значений!

Разберем рабочий пример использования метода:


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

Если во время вызова метода Свернуть() вы получаете ошибку "Неверное имя колонки", убедитесь, что:

  1. Колонки с указанными именами действительно добавлены в таблицу значений.
  2. В колонке суммирования (в нашем случае "Количество") лежат исключительно числовые типы данных, а не строки "1" из JSON.

Вариант Б. Профессиональный подход — Запрос к Таблице Значений

Использование метода Свернуть() имеет ограничения. Что если вам нужно сгруппировать по фамилии, но при этом посчитать не сумму готового поля, а количество строк, или наложить сложные условия? Здесь на помощь приходят запросы к таблицам значений.

Рассмотрим пример реализации группировки через временные таблицы в запросе:


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

Важное требование: Чтобы запрос к таблице значений успешно выполнился, все колонки переданной таблицы должны быть строго типизированы (иметь явное описание типов при создании колонок в методе Добавить()), иначе платформа выбросит исключение.

4. Проверка заполнения реквизитов таблицы на клиенте

Вернемся к финальному вопросу автора обсуждения: как проверить на клиенте, заполнил ли пользователь обязательные поля в нашей таблице? Попытка использовать метод РеквизитФормыВЗначение() на клиенте завершится неудачей, так как этот метод работает только в контексте сервера и является очень тяжелым для системы.

Посмотрим на два изящных способа решения этой задачи.

Способ 1. Быстрый программный обход на клиенте

Поскольку данные таблицы формы представлены типом ДанныеФормыКоллекция, мы можем легко обойти строки в цикле прямо на стороне клиента. Для проверки пустого значения воспользуемся универсальной функцией ЗначениеЗаполнено(), которая отлично работает на клиенте.

Свяжем сообщение об ошибке с конкретной ячейкой на форме, чтобы пользователь сразу понял, где допущена ошибка:


&НаКлиенте
Процедура ПроверитьЗаполнениеТаблицыНаКлиенте()
    
    Отказ = Ложь;
    
    Для Каждого СтрокаТаблицы Из Объект.СотрудникиТаблица Цикл
        
        Если Не ЗначениеЗаполнено(СтрокаТаблицы.Фамилия) Тогда
            
            // Находим индекс строки для точной адресации сообщения
            ИндексСтроки = Объект.СотрудникиТаблица.Индекс(СтрокаТаблицы);
            
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Поле 'Фамилия' обязательно для заполнения!";
            // Формируем путь к конкретной ячейке на форме
            Сообщение.Поле = "Объект.СотрудникиТаблица[" + ИндексСтроки + "].Фамилия";
            Сообщение.Сообщить();
            
            Отказ = Истина;
            
        КонецЕсли;
        
    КонецЦикла;
    
    Если Отказ Тогда
        ПоказатьПредупреждение(, "Обнаружены незаполненные поля в списке сотрудников!");
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Декларативная проверка силами самой платформы 1С (Рекомендуемый)

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

  1. Откроем редактор управляемой формы в Конфигураторе, перейдем на вкладку «Реквизиты».
  2. Развернем наш реквизит формы (типа ТаблицаЗначений) СотрудникиТаблица и выберем нужную колонку (например, Фамилия).
  3. В панели свойств этой колонки найдем свойство «Проверка заполнения» и установим его в значение «Выдавать ошибку».
  4. В свойствах элемента управления (поля ввода в таблице на форме) включим флаг «Автоотметка незаполненного» (это визуально подчеркнет пустое поле красным пунктиром).

Теперь перед выполнением целевого действия на клиенте (например, перед проведением или сохранением данных) нам достаточно вызвать стандартный метод формы:


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

Использование встроенных платформенных проверок — это самый надежный, быстрый и профессиональный способ валидации данных в современной экосистеме 1С.

← На главную