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