Как предотвратить добавление дублирующихся элементов в список значений на управляемой форме?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с управляемыми формами в 1С часто возникает задача обеспечить уникальность элементов в СписокЗначений, который отображается на форме в виде таблицы. Стандартная команда Добавить в таблице формы работает по следующему алгоритму: сначала создается новая (пустая) строка, а затем открывается форма выбора или активируется поле ввода для заполнения значения. Именно этот разрыв во времени между созданием строки и выбором значения создает сложности при проверке на дубликаты.

Рассмотрим подробно, почему стандартные методы иногда дают сбой и как правильно реализовать проверку, чтобы в списке не оставалось пустых строк или повторяющихся элементов. Проанализируем несколько подходов: от простых манипуляций с событиями до полной замены логики добавления.

Метод 1. Программное удаление строки в событии «ОбработкаВыбора»

Многие разработчики пытаются использовать событие ОбработкаВыбора у элемента формы (поля ввода в колонке таблицы). Однако установка параметра СтандартнаяОбработка = Ложь в этом случае лишь отменяет помещение выбранного значения в строку, но сама строка, созданная командой Добавить, остается в таблице пустой. Чтобы решить проблему, нам необходимо принудительно удалить эту строку, если выяснилось, что выбранный элемент уже существует в списке.

Выясним, как это реализовать программно. Нам потребуется обратиться к текущим данным таблицы и проверить их наличие в основной коллекции. Разберем пример кода:


&НаКлиенте
Процедура СписокЗначенийОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    // Отменяем стандартную вставку значения, так как будем управлять процессом сами
    СтандартнаяОбработка = Ложь;
    
    // Проверяем, нет ли уже такого значения в нашем списке
    // Поиск выполняется по всей коллекции, кроме текущей редактируемой строки
    ЭлементСписка = Объект.СписокЗначений.НайтиПоЗначению(ВыбранноеЗначение);
    
    Если ЭлементСписка = Неопределено Тогда
        // Если значение не найдено, присваиваем его в текущую строку
        ТекущаяСтрока = Элементы.СписокЗначенийТаблица.ТекущиеДанные;
        ТекущаяСтрока.Значение = ВыбранноеЗначение;
    Иначе
        // Если значение уже есть, выводим предупреждение пользователю
        ПоказатьПредупреждение(, "Такой элемент уже добавлен в список!");
        
        // Удаляем пустую строку, которая была создана нажатием кнопки "Добавить"
        ИдентификаторСтроки = Элементы.СписокЗначенийТаблица.ТекущаяСтрока;
        Если ИдентификаторСтроки <> Неопределено Тогда
            Объект.СписокЗначений.Удалить(Объект.СписокЗначений.НайтиПоИдентификатору(ИдентификаторСтроки));
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Метод 2. Переопределение стандартной команды «Добавить»

Проанализируем более «чистый» способ, который исключает само появление временной пустой строки. Вместо того чтобы бороться с последствиями стандартного добавления, мы можем создать свою команду или перехватить действие стандартной кнопки в командной панели.

Для этого в свойствах таблицы формы найдем список команд и создадим собственную команду ДобавитьБезДублей. Разберем по шагам логику её работы:

  1. Сначала вызываем форму выбора или список доступных значений.
  2. После выбора значения проверяем его наличие в списке.
  3. Только если значение уникально, программно добавляем новую строку в СписокЗначений.

Посмотрим на пример реализации с использованием метода ПоказатьВыборИзСписка (актуально, если набор значений ограничен):


&НаКлиенте
Процедура КомандаДобавить(Команда)
    
    // Формируем список для выбора (например, из справочника или массива)
    СписокДляВыбора = ПолучитьДоступныеЗначенияНаСервере();
    
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораЗначения", ЭтотОбъект);
    ПоказатьВыборИзСписка(ОписаниеОповещения, СписокДляВыбора);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораЗначения(ВыбранныйЭлемент, Параметры) Экспорт
    
    Если ВыбранныйЭлемент = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Ищем дубликат
    Если Объект.СписокЗначений.НайтиПоЗначению(ВыбранныйЭлемент.Значение) = Неопределено Тогда
        // Добавляем только уникальное
        НоваяСтрока = Объект.СписокЗначений.Добавить();
        НоваяСтрока.Значение = ВыбранныйЭлемент.Значение;
    Иначе
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Данное значение уже присутствует в списке.");
    КонецЕсли;
    
КонецПроцедуры

Метод 3. Динамическая фильтрация списка выбора (Событие «НачалоВыбора»)

Рассмотрим продвинутый вариант, который повышает удобство работы пользователя (UX). Вместо того чтобы выдавать ошибку ПОСЛЕ выбора, мы можем просто скрыть уже добавленные элементы из формы выбора. Это исключит саму возможность ошибки.

Для реализации этого метода используем событие НачалоВыбора для поля в таблице. Проанализируем алгоритм:

  1. При нажатии на кнопку выбора в строке таблицы собираем массив всех значений, которые уже есть в СписокЗначений.
  2. Передаем этот массив в параметры открываемой формы выбора в качестве отбора (используя вид сравнения НеВСписке).

&НаКлиенте
Процедура СписокЗначенийЗначениеНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Собираем массив существующих значений
    ИсключаемыеЗначения = Новый Массив;
    Для Каждого Стр Из Объект.СписокЗначений Цикл
        Если ЗначениеЗаполнено(Стр.Значение) Тогда
            ИсключаемыеЗначения.Добавить(Стр.Значение);
        КонецЕсли;
    КонецЦикла;
    
    ПараметрыВыбора = Новый Структура;
    
    // Формируем отбор для формы выбора справочника (например, Номенклатура)
    Отбор = Новый Структура("Ссылка", Новый ПараметрВыбора"Отбор.Ссылка", ИсключаемыеЗначения, ВидСравненияКомпоновкиДанных.НеВСписке));
    // Примечание: Синтаксис передачи отбора зависит от конкретной задачи и типа данных
    
    ПараметрыФормы = Новый Структура("Отбор", Отбор);
    ОткрытьФорму("Справочник.ВашСправочник.ФормаВыбора", ПараметрыФормы, Элемент);
    
КонецПроцедуры

Метод 4. Использование механизма «Подбор»

Как справедливо заметил автор темы, иногда самым эффективным решением является полный отказ от команды Добавить в пользу стандартного механизма подбора. Рассмотрим преимущества этого подхода:

Во-первых, форма подбора позволяет выбрать сразу несколько элементов. Во-вторых, в обработчике события ОбработкаВыбора формы подбора можно реализовать лаконичный цикл проверки. Если элемент уже присутствует в коллекции — мы просто игнорируем его и переходим к следующему, не беспокоя пользователя лишними сообщениями о каждой строке. Для реализации пакетного сбора данных можно использовать универсальную форму ввода и подбора значений различных типов.

Проанализируем пример обработки результата подбора:


&НаКлиенте
Процедура СписокЗначенийОбработкаПодбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    // Если подбор вернул массив значений
    Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
        Для Каждого ЭлементМассива Из ВыбранноеЗначение Цикл
            // Проверка на уникальность
            Если Объект.СписокЗначений.НайтиПоЗначению(ЭлементМассива) = Неопределено Тогда
                Объект.СписокЗначений.Добавить(ЭлементМассива);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Важные технические нюансы

При реализации любого из перечисленных методов следует помнить о нескольких особенностях платформы 1С:

Подводя итог, можно сказать, что наиболее надежным и профессиональным способом является Метод 2 (Своя команда) или Метод 4 (Подбор). Они позволяют полностью контролировать жизненный цикл строки данных и избавляют пользователя от необходимости видеть пустые строки или исправлять ошибки после их совершения.

← На главную