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