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