Удаление выбранных элементов

Библиотека Choices.js предоставляет несколько уровней управления выбранными значениями: от встроенного UI-удаления до программного API и событийной модели. Удаление выбранных элементов является частью внутреннего состояния инстанса и синхронизируется как с DOM, так и с исходным <select> или виртуальным списком опций.

Архитектура удаления строится вокруг трёх основных механизмов:

  • удаление через интерфейс (remove button у выбранного элемента);
  • программное удаление через методы API;
  • удаление через изменение состояния данных (store / value binding).

Встроенное удаление через интерфейс пользователя

Опция removeItemButton

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

const choices = new Choices('#select', {
  removeItemButton: true
});

После активации данной опции каждый выбранный элемент получает кнопку удаления (×), при нажатии на которую происходит:

  • удаление элемента из массива выбранных значений;
  • обновление UI;
  • синхронизация с оригинальным <select>;
  • генерация события removeItem.

Поведение кнопки полностью управляется библиотекой и не требует дополнительного кода.


Программное удаление выбранных элементов

Удаление конкретного значения

Choices.js предоставляет метод removeItemByValue, предназначенный для удаления элемента по его значению.

choices.removeItemByValue('value_1');

При вызове метода происходит:

  • поиск элемента в текущем наборе выбранных значений;
  • удаление из внутреннего состояния;
  • обновление отображения;
  • обновление DOM <select>.

Особенности поведения:

  • если значение отсутствует, операция игнорируется;
  • метод применим как к single, так и multi select;
  • в multi-select удаляется только одно совпадение значения.

Удаление объекта выбора

Внутренне Choices.js оперирует объектами выбора, содержащими:

  • value
  • label
  • selected
  • disabled

Некоторые версии API позволяют работать через объект:

choices.removeActiveItems();

Этот метод удаляет все активные выбранные элементы.


Очистка всех выбранных элементов

Полное сбрасывание выбора осуществляется через:

choices.removeActiveItems();

Поведение метода:

  • очищает массив выбранных значений;
  • снимает все визуальные элементы выбранных тегов;
  • сбрасывает состояние <select>;
  • вызывает событие изменения.

Альтернативный подход через состояние:

choices.setChoiceByValue([]);

Управление удалением через состояние выбора

Сброс через setChoiceByValue

Метод setChoiceByValue может использоваться для переопределения текущего выбора.

choices.setChoiceByValue(['a', 'b']);

Передача пустого массива фактически эквивалентна очистке:

choices.setChoiceByValue([]);

Этот подход полезен при:

  • синхронизации с серверными данными;
  • восстановлении состояния формы;
  • реализации кастомной логики фильтрации.

События удаления элементов

Choices.js предоставляет событийную модель, позволяющую реагировать на удаление элементов.

Событие removeItem

const element = document.querySelector('#select');

element.addEventListener('removeItem', function(event) {
  console.log(event.detail);
});

Содержимое event.detail:

  • value — удалённое значение;
  • label — отображаемый текст;
  • id — внутренний идентификатор;
  • choice — объект выбора.

Событие вызывается при:

  • клике по кнопке удаления;
  • программном вызове removeItemByValue;
  • очистке всех элементов.

Событие change

Любое удаление также вызывает стандартное событие change, что обеспечивает совместимость с нативными формами.

element.addEventListener('change', function(event) {
  console.log('Изменение состояния выбора');
});

Взаимодействие с disabled-элементами

Удаление невозможно для элементов, которые:

  • помечены как disabled;
  • заблокированы через конфигурацию;
  • добавлены как фиксированные значения.

Пример:

choices.setChoices([
  { value: 'a', label: 'A', disabled: true }
]);

Такой элемент:

  • отображается, но не может быть удалён;
  • не реагирует на кнопку удаления;
  • игнорируется API удаления.

Удаление в режиме single select

В режиме одиночного выбора поведение отличается:

  • выбранный элемент заменяется новым;
  • удаление фактически означает очистку перед установкой нового значения;
  • removeItemByValue очищает текущее значение.

Пример:

choices.setChoiceByValue('value_1');
choices.removeItemByValue('value_1');

После выполнения состояние становится пустым.


Удаление в режиме multiple select

В multi-select режиме каждый элемент независим:

  • каждый выбранный элемент имеет собственный DOM-узел;
  • удаление происходит точечно;
  • состояние хранится как массив значений.

Пример удаления:

choices.removeItemByValue('value_2');

После выполнения:

  • значение удаляется из массива;
  • остальные значения сохраняются;
  • UI обновляется частично.

Кастомизация поведения кнопки удаления

Кнопка удаления может быть стилизована или заменена через CSS.

.choices__button {
  background: transparent;
  border: none;
  cursor: pointer;
}

Также можно полностью отключить стандартное удаление:

const choices = new Choices('#select', {
  removeItemButton: false
});

И реализовать кастомную логику:

document.addEventListener('click', (e) => {
  if (e.target.classList.contains('custom-remove')) {
    choices.removeItemByValue(e.target.dataset.value);
  }
});

Синхронизация с оригинальным <select>

Choices.js всегда поддерживает синхронизацию состояния:

  • удаление обновляет option.selected = false;
  • DOM <select> остаётся источником истины для формы;
  • при сабмите формы удалённые значения не отправляются.

Пример поведения:

<select id="select" multiple>
  <option value="1">One</option>
  <option value="2">Two</option>
</select>

После удаления значения:

  • соответствующий <option> теряет атрибут selected;
  • форма отправляет только актуальные данные.

Программная блокировка удаления

Удаление можно частично контролировать через перехват событий.

Отмена удаления через логику

element.addEventListener('removeItem', function(event) {
  if (event.detail.value === 'protected') {
    event.preventDefault();
  }
});

Хотя не все версии Choices.js поддерживают полноценный preventDefault для этого события, часто применяется обходной путь:

element.addEventListener('removeItem', function(event) {
  if (event.detail.value === 'protected') {
    setTimeout(() => {
      choices.setChoiceByValue('protected');
    }, 0);
  }
});

Массовое удаление с фильтрацией

Расширенные сценарии требуют удаления по условию:

const values = choices.getValue(true);

values.forEach(value => {
  if (value.startsWith('temp_')) {
    choices.removeItemByValue(value);
  }
});

Такая схема применяется при:

  • очистке временных данных;
  • синхронизации с сервером;
  • фильтрации устаревших значений.

Особенности производительности

При большом количестве выбранных элементов:

  • множественные вызовы removeItemByValue могут быть дорогими;
  • предпочтительно использовать removeActiveItems для полной очистки;
  • пакетное обновление состояния уменьшает количество перерисовок.

Оптимизированный подход:

choices.removeActiveItems();
choices.setChoiceByValue(filteredValues);

Сценарии интеграции с внешними данными

При работе с API часто возникает необходимость синхронного удаления:

async function deleteAndSync(value) {
  await fetch(`/api/delete/${value}`, { method: 'DELETE' });
  choices.removeItemByValue(value);
}

В этом случае Choices.js выступает только как UI-слой, а источник истины находится на сервере.


Поведение при reset формы

При сбросе формы (<form>.reset()):

  • Choices.js восстанавливает исходные значения <select>;
  • удалённые элементы возвращаются, если они были в initial state;
  • кастомное состояние может быть потеряно.

Для контроля используется:

choices.clearStore();

или повторная инициализация инстанса.