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