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