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