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