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