СписокЗначений в 1С 8.3: Добавить, Вставить, ЗагрузитьЗначения и заполнение списка выбора на форме

· 9 мин

Содержание

Чтобы добавить значение в список значений 1С, вызовите у объекта метод Добавить(): Список.Добавить("Москва");. Метод кладёт элемент в конец списка и возвращает его, так что представление и пометку можно задать сразу или позже.

Частое заблуждение — считать, что Добавить() отсекает повторы, как множество. Не отсекает: два вызова с одним значением дадут два элемента. Уникальность, порядок и массовое заполнение держит сам программист, и ниже показано, как это сделать без лишних циклов. Всё описанное относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: БП, ЗУП и УТ используют один и тот же встроенный язык.

Создание объекта СписокЗначений перед добавлением значений

Список значений — универсальная коллекция встроенного языка. Каждый её элемент имеет тип ЭлементСпискаЗначений и четыре свойства:

СвойствоЧто хранитПример
ЗначениеСамо значение любого типаСправочники.Склады.Основной
ПредставлениеСтроку, которую видит пользователь"Основной склад"
ПометкаБулево, флажок у элементаИстина
КартинкаЗначение типа Картинкакартинка из библиотеки

Создаётся список конструктором без параметров:

Список = Новый СписокЗначений;

Сразу после создания список пуст: Список.Количество() вернёт 0. Индексы элементов начинаются с нуля, то есть последний элемент лежит по индексу Количество() - 1.

Реквизит формы типа СписокЗначений

Если список нужен на форме, его не создают конструктором. Добавьте реквизит формы с типом СписокЗначений в редакторе формы, и платформа создаст объект вместе с формой. В коде к нему обращаются по имени реквизита:

&НаКлиенте
Процедура ДобавитьГород(Команда)
    ВыбранныеГорода.Добавить("Самара");
КонецПроцедуры

Повторно создавать объект через Новый СписокЗначений в такой форме не нужно. Чтобы начать заполнение заново, достаточно вызвать ВыбранныеГорода.Очистить(): реквизит останется тем же, а все элементы будут удалены.

Где список значений встречается чаще всего:

  • 📌 параметр запроса для условия В (&Список);
  • 📌 список выбора поля ввода на управляемой форме;
  • 📌 реквизит формы для отметки нескольких вариантов флажками;
  • 📌 передача набора значений между клиентом и сервером.

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

Метод Добавить: синтаксис и параметры

Полная форма вызова:

Элемент = Список.Добавить(Значение, Представление, Пометка, Картинка);

Все параметры необязательные:

  1. Значение — то, что кладём в список. Тип любой: число, строка, дата, ссылка, структура.
  2. Представление — строка для пользователя. Если не задана, при выводе используется стандартное представление значения.
  3. Пометка — булево. По умолчанию Ложь.
  4. Картинка — значение типа Картинка.

Метод возвращает созданный ЭлементСпискаЗначений. Возвращаемое значение часто игнорируют, но им удобно пользоваться:

Список = Новый СписокЗначений;

// Простое добавление: представление не задано
Список.Добавить(100);
Список.Добавить("Москва");
Список.Добавить(ТекущаяДата());

// Сохраняем ссылку на элемент и дописываем свойства позже
Элемент = Список.Добавить(5, "Пять процентов");
Элемент.Пометка = Истина;

Если вызвать Добавить() вообще без параметров, в список попадёт элемент со значением Неопределено. Такой элемент потом заполняют через свойства:

Элемент = Список.Добавить();
Элемент.Значение = "НДС 20%";
Элемент.Представление = "Основная ставка";

Пропуск параметра оставляет запятую на месте: Список.Добавить(Склад, , Истина) — значение и пометка без представления. Если перепутать порядок, булево уйдёт в представление, и пользователь увидит слово «Да» вместо названия.

Добавление элементов с представлением, пометкой и картинкой

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

СписокСтавок = Новый СписокЗначений;
СписокСтавок.Добавить(0,  "Без НДС");
СписокСтавок.Добавить(10, "НДС 10%");
СписокСтавок.Добавить(20, "НДС 20%");

В выпадающем списке пользователь выберет «НДС 20%», а код получит число 20.

Пометки для множественного выбора

Пометка нужна, когда пользователь отмечает несколько вариантов. Типичный пример — фильтр по складам:

Склады = Новый СписокЗначений;
Выборка = Справочники.Склады.Выбрать();
Пока Выборка.Следующий() Цикл
    Склады.Добавить(Выборка.Ссылка, Выборка.Наименование, Истина);
КонецЦикла;

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

Склады.ЗаполнитьПометки(Ложь); // снять все флажки

Собрать только отмеченные значения можно обходом:

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

Картинка у элемента

Картинку берут из общих картинок конфигурации через БиблиотекаКартинок:

// ИмяКартинки — имя общей картинки из ветки «Общие картинки» вашей конфигурации
Список.Добавить("Ошибка", "Требует внимания", , БиблиотекаКартинок.ИмяКартинки);

Подставьте имя картинки, которая реально есть в дереве метаданных. Несуществующее имя даст ошибку при выполнении.

Вставка элемента по индексу и перемещение внутри списка

Добавить() всегда пишет в конец. Чтобы поставить значение на конкретное место, используйте Вставить(). Первым параметром идёт индекс, остальные совпадают с Добавить():

Список = Новый СписокЗначений;
Список.Добавить("Второй");
Список.Добавить("Третий");

Список.Вставить(0, "Первый");          // в начало списка
Список.Вставить(Список.Количество(), "Последний"); // в конец

После этого порядок такой: «Первый», «Второй», «Третий», «Последний». Индекс 0 — начало, индекс, равный Количество(), — позиция за последним элементом.

Типовой приём — пункт «Все» или «<не выбрано>» в начале списка выбора: Список.Вставить(0, Неопределено, "Все склады"). Его добавляют после заполнения, чтобы он не зависел от порядка выборки.

Перемещение: метод Сдвинуть

Сдвинуть() переставляет уже существующий элемент. Первый параметр — элемент или его индекс, второй — смещение: отрицательное двигает вверх, положительное вниз.

Элемент = Список.НайтиПоЗначению("Последний");
Список.Сдвинуть(Элемент, -1); // на одну позицию к началу

Узнать текущую позицию элемента позволяет Список.Индекс(Элемент), получить элемент по позиции — Список.Получить(Индекс) или Список[Индекс].

Сортировка вместо ручной перестановки

Если нужен алфавитный или числовой порядок, не переставляйте элементы вручную — отсортируйте:

Список.СортироватьПоПредставлению(НаправлениеСортировки.Возр);
Список.СортироватьПоЗначению(НаправлениеСортировки.Убыв);

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

Массовое добавление значений из массива, запроса и других коллекций

Добавлять сотни элементов по одному в цикле можно, но для простых случаев есть короче.

Из массива: ЗагрузитьЗначения

Города = Новый Массив;
Города.Добавить("Москва");
Города.Добавить("Казань");
Города.Добавить("Пермь");

Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(Города);

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

Для Каждого Город Из Города Цикл
    Список.Добавить(Город);
КонецЦикла;

Обратная операция — Список.ВыгрузитьЗначения(), она возвращает массив значений без представлений и пометок.

Из результата запроса

Когда представление не нужно, выгрузите колонку в массив:

Запрос = Новый Запрос(
"ВЫБРАТЬ
|    Номенклатура.Ссылка КАК Ссылка
|ИЗ
|    Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|    НЕ Номенклатура.ПометкаУдаления");

Ссылки = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(Ссылки);

Если нужна своя подпись, обходите выборку:

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Список.Добавить(Выборка.Ссылка, Строка(Выборка.Ссылка));
КонецЦикла;

Из таблицы значений, структуры и соответствия

ИсточникКак переноситьЧто попадает в значение
МассивЗагрузитьЗначения() или циклэлементы массива
ТаблицаЗначенийВыгрузитьКолонку() → ЗагрузитьЗначения()одна колонка
Структурацикл Для КаждогоКлючИЗначение.Значение, ключ — в представление
Соответствиецикл Для Каждогото же, что для структуры

Пример со соответствием, где ключ — код, а значение — подпись:

Статусы = Новый Соответствие;
Статусы.Вставить("new",  "Новый");
Статусы.Вставить("done", "Выполнен");

Список = Новый СписокЗначений;
Для Каждого КлючИЗначение Из Статусы Цикл
    Список.Добавить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
КонецЦикла;

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

Список как параметр запроса

Заполненный список сразу подходит для условия В:

Запрос.УстановитьПараметр("Склады", Склады);
// в тексте запроса: ГДЕ Остатки.Склад В (&Склады)

В условие попадут все значения списка, пометки при этом не учитываются. Чтобы отбор шёл только по отмеченным, передайте массив Отмеченные из примера выше.

Добавление значения в список выбора поля на форме

Частый практический случай — добавить вариант в выпадающий список поля ввода. Свойство СписокВыбора у поля формы — тот же СписокЗначений, поэтому работают все методы выше.

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

Чтобы пользователь выбирал только из списка и не вводил свой текст, включите у поля свойство РежимВыбораИзСписка. Его можно поставить в палитре свойств поля в конфигураторе или кодом: Элементы.ВидОплаты.РежимВыбораИзСписка = Истина;.

В типовой конфигурации на поддержке форму правят через расширение, а не в основной конфигурации: так доработка переживает обновление. Код выше переносится в расширение без изменений, только процедура оформляется как обработчик расширения.

Для диалога «выберите один вариант» на клиенте используется Список.ПоказатьВыборЭлемента(Оповещение, "Заголовок"), для отметки нескольких — Список.ПоказатьОтметкуЭлементов(Оповещение, "Заголовок"). Оба метода не модальные, результат приходит в процедуру оповещения.

Ошибки при добавлении значений в список и отладка

Диагностика: выберите симптом

Как не допустить дублей

Функция-обёртка проверяет наличие значения перед добавлением:

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

НайтиПоЗначению() сравнивает значения так же, как оператор =. Для ссылок, чисел, строк и дат это работает ожидаемо. Две разные структуры с одинаковым содержимым считаются разными значениями, и проверка их не поймает.

На больших объёмах (десятки тысяч элементов) поиск по списку перед каждым добавлением идёт медленно, потому что это перебор. Быстрее держать рядом Соответствие как индекс уже добавленных значений и проверять ключ через него.

Удаление в цикле

Если при обходе нужно удалять элементы, идите с конца, иначе индексы сдвинутся и часть элементов будет пропущена:

Для Сч = 1 По Список.Количество() Цикл
    Индекс = Список.Количество() - Сч;
    Если Не Список[Индекс].Пометка Тогда
        Список.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

Граница цикла вычисляется один раз при входе, а индекс считается от текущего количества. После удаления элемента с конца все ещё не проверенные элементы стоят на прежних местах, поэтому пропусков нет.

Как посмотреть содержимое списка

В отладчике поставьте точку останова после заполнения и откройте окно вычисления выражения (Shift+F9) для переменной списка. Там видны значение, представление и пометка каждого элемента.

Без отладчика содержимое быстро выводится в сообщения:

Для Каждого Элемент Из Список Цикл
    Сообщить(СтрШаблон("[%1] %2 = %3, пометка: %4",
        Формат(Список.Индекс(Элемент), "ЧН=0; ЧГ=0"),
        Элемент.Представление,
        Элемент.Значение,
        Элемент.Пометка));
КонецЦикла;

Формат с ЧН=0 нужен, чтобы индекс 0 выводился цифрой, а не пустой строкой.

Частые вопросы

Можно ли добавить в список значений другой список или массив целиком как один элемент?
Да. Список.Добавить(Массив) положит массив в значение одного элемента. Чтобы добавить его элементы по отдельности, нужен цикл или ЗагрузитьЗначения().
Чем СписокЗначений отличается от Массива при передаче между клиентом и сервером?
Обе коллекции передаются, если внутри лежат значения, допустимые на клиенте. Ссылки и примитивные типы проходят; объекты вроде СправочникОбъект или Запрос — нет.
Как ограничить тип значений в списке?
У списка есть свойство ТипЗначения типа ОписаниеТипов. Его задают, когда пользователь вводит значения в список сам, например в реквизите формы.
Как изменить представление у уже добавленного элемента?
Найдите элемент через НайтиПоЗначению() или по индексу и присвойте новое значение свойству Представление. Пересоздавать элемент не нужно.
Сохраняется ли порядок элементов в списке значений?
Да. Элементы идут в порядке добавления, пока вы не вызовете Вставить(), Сдвинуть() или сортировку.