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