Включение и настройка поиска

Механизм поиска в библиотеке Choices.js предназначен для быстрого нахождения элементов внутри выпадающего списка. Особенно важен поиск при работе с большим количеством опций, динамически загружаемыми данными и множественным выбором.

Поиск работает для:

  • <select>
  • <input>
  • множественного выбора
  • тегов
  • асинхронных списков

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


Базовое включение поиска

По умолчанию поиск активирован для большинства select-элементов.

Пример стандартной инициализации:

<select id="city-select">
  <option>Алматы</option>
  <option>Астана</option>
  <option>Караганда</option>
  <option>Шымкент</option>
</select>
const choices = new Choices('#city-select');

После инициализации появляется поле ввода, позволяющее фильтровать элементы списка.


Принудительное включение поиска

Для явного включения используется параметр searchEnabled.

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

Это особенно полезно при:

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

Полное отключение поиска

Иногда поиск мешает интерфейсу, особенно если список содержит небольшое количество элементов.

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

После отключения:

  • поле ввода не отображается;
  • фильтрация не выполняется;
  • клавиатурный поиск становится недоступен.

Минимальное количество элементов для активации поиска

Параметр searchChoices определяет, должен ли поиск работать вообще.

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

Если установить:

searchChoices: false

то:

  • поле поиска может отображаться;
  • но фильтрация списка производиться не будет.

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

  • удалённом поиске;
  • серверной фильтрации;
  • работе через AJAX.

Ограничение поиска по количеству элементов

Параметр searchFloor задаёт минимальное количество символов перед началом поиска.

const choices = new Choices('#city-select', {
  searchFloor: 3
});

Поведение:

Количество символов Выполняется поиск
1 Нет
2 Нет
3 Да
4 Да

Такой подход снижает:

  • нагрузку на DOM;
  • количество операций фильтрации;
  • число запросов при серверном поиске.

Ограничение количества результатов

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

const choices = new Choices('#city-select', {
  searchResultLimit: 5
});

Если найдено 100 совпадений, отобразятся только первые 5.

Особенно полезно:

  • в больших справочниках;
  • при поиске стран;
  • при работе с тысячами элементов.

Настройка позиции поиска

Поле поиска может располагаться в разных частях интерфейса.

Параметр:

searchFields

указывает, по каким полям выполнять поиск.


Поиск по label

Стандартный вариант:

const choices = new Choices('#city-select', {
  searchFields: ['label']
});

Поиск будет происходить по отображаемому тексту.

Например:

<option value="kz">Казахстан</option>

Поиск сработает по слову:

Казахстан

Поиск по value

const choices = new Choices('#city-select', {
  searchFields: ['value']
});

Теперь поиск выполняется по атрибуту value.

Пример:

<option value="kazakhstan">Казахстан</option>

Поиск:

kaz

найдёт элемент.


Поиск одновременно по нескольким полям

Наиболее гибкий вариант:

const choices = new Choices('#city-select', {
  searchFields: ['label', 'value']
});

Choices.js проверяет совпадения сразу в нескольких свойствах.

Это особенно удобно для:

  • кодов стран;
  • SKU товаров;
  • внутренних идентификаторов;
  • multilingual-интерфейсов.

Поиск по customProperties

Choices.js поддерживает дополнительные поля.

Пример:

const choices = new Choices('#city-select', {
  choices: [
    {
      value: 'kz',
      label: 'Казахстан',
      customProperties: {
        region: 'Asia'
      }
    },
    {
      value: 'de',
      label: 'Германия',
      customProperties: {
        region: 'Europe'
      }
    }
  ],
  searchFields: ['label', 'customProperties.region']
});

Теперь поиск по слову:

Europe

найдёт Германию.


Работа searchFields с вложенными объектами

Поддерживается dot notation.

Пример:

searchFields: [
  'label',
  'customProperties.meta.code'
]

Структура:

customProperties: {
  meta: {
    code: 'EU-001'
  }
}

Поиск:

EU

успешно найдёт элемент.


Настройка placeholder для поиска

Текст внутри поля поиска задаётся через:

searchPlaceholderValue

Пример:

const choices = new Choices('#city-select', {
  searchPlaceholderValue: 'Введите страну'
});

Интерфейс становится понятнее при сложных списках.


Placeholder отдельно для select и input

Choices.js различает:

  • placeholder самого элемента;
  • placeholder поиска.

Пример:

const choices = new Choices('#city-select', {
  placeholder: true,
  placeholderValue: 'Выберите страну',
  searchPlaceholderValue: 'Поиск страны'
});

Разница:

Элемент Назначение
placeholderValue Текст выбора
searchPlaceholderValue Текст поля поиска

Поиск без сортировки результатов

По умолчанию результаты могут изменять порядок.

Чтобы сохранить оригинальную последовательность:

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

Это важно:

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

Сортировка результатов поиска

Choices.js позволяет управлять сортировкой через callback.

const choices = new Choices('#city-select', {
  sorter: (a, b) => {
    return a.label.localeCompare(b.label);
  }
});

Можно:

  • сортировать по алфавиту;
  • по длине;
  • по популярности;
  • по пользовательскому весу.

Пользовательская логика поиска

Для сложной фильтрации применяется fuseOptions.

Choices.js использует библиотеку Fuse.js.

Пример:

const choices = new Choices('#city-select', {
  fuseOptions: {
    includeScore: true,
    threshold: 0.2
  }
});

Параметр threshold

Ключевой параметр Fuse.js:

threshold

Определяет строгость поиска.

Значение Поведение
0 Только точные совпадения
0.2 Очень строгий поиск
0.4 Умеренный
0.6 Мягкий
1 Практически любые совпадения

Нечёткий поиск

Choices.js поддерживает fuzzy search.

Пример:

const choices = new Choices('#city-select', {
  fuseOptions: {
    threshold: 0.4
  }
});

Запрос:

Казхстан

сможет найти:

Казахстан

Поиск без учёта регистра

Поиск в Choices.js регистронезависим по умолчанию.

Запросы:

алм
АЛМ
АлМ

дадут одинаковый результат.


Поиск с учётом акцентов и диакритики

Fuse.js умеет нормализовать символы.

Пример:

const choices = new Choices('#city-select', {
  fuseOptions: {
    ignoreLocation: true
  }
});

Особенно полезно для:

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

Поиск по началу строки

Иногда требуется искать только префикс.

Пример кастомной настройки:

const choices = new Choices('#city-select', {
  fuseOptions: {
    threshold: 0,
    distance: 0
  }
});

Теперь:

Каз

найдёт:

Казахстан

но не:

Южный Казахстан

Обработка события поиска

Choices.js генерирует событие search.

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

element.addEventListener('search', event => {
  console.log(event.detail.value);
});

В detail.value находится текущая строка поиска.


Пример:

element.addEventListener('search', event => {
  console.log(event.detail);
});

Результат:

{
  value: 'каз'
}

Очистка строки поиска

Программная очистка:

choices.input.element.value = '';

После очистки можно обновить список:

choices.showDropdown();

Поиск в multiple select

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

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

Преимущества:

  • быстрый поиск тегов;
  • удобная фильтрация;
  • снижение визуальной перегрузки.

Производительность поиска

При работе с тысячами элементов необходимо учитывать:

  • скорость рендера;
  • стоимость фильтрации;
  • обновление DOM.

Оптимизации:

const choices = new Choices('#big-list', {
  searchResultLimit: 20,
  searchFloor: 2,
  shouldSort: false
});

Поиск с AJAX

При удалённой загрузке локальный поиск часто отключается.

const choices = new Choices('#users', {
  searchChoices: false
});

Далее используется собственная логика:

element.addEventListener('search', async event => {
  const query = event.detail.value;

  const response = await fetch(`/users?q=${query}`);
  const users = await response.json();

  choices.clearChoices();

  choices.setChoices(users, 'id', 'name', true);
});

Debounce для поиска

Без debounce серверный поиск создаёт слишком много запросов.

Пример:

function debounce(fn, delay) {
  let timer;

  return (...args) => {
    clearTimeout(timer);

    timer = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}

Использование:

const searchHandler = debounce(async event => {
  const query = event.detail.value;

  const response = await fetch(`/users?q=${query}`);
  const users = await response.json();

  choices.clearChoices();
  choices.setChoices(users, 'id', 'name', true);
}, 300);

element.addEventListener('search', searchHandler);

Поиск и динамические данные

При обновлении данных Choices.js автоматически перестраивает индекс поиска.

Пример:

choices.setChoices([
  { value: 1, label: 'JavaScript' },
  { value: 2, label: 'TypeScript' }
], 'value', 'label', true);

После обновления поиск сразу начинает работать по новым элементам.


Локализация текста отсутствия результатов

Сообщение задаётся через:

noResultsText

Пример:

const choices = new Choices('#city-select', {
  noResultsText: 'Ничего не найдено'
});

Настройка текста поиска

Дополнительные параметры интерфейса:

const choices = new Choices('#city-select', {
  loadingText: 'Загрузка...',
  noChoicesText: 'Нет вариантов',
  itemSelectText: 'Нажмите для выбора'
});

Поиск и accessibility

Choices.js поддерживает:

  • клавиатурную навигацию;
  • ARIA-атрибуты;
  • управление через Tab;
  • поиск без мыши.

Поле поиска автоматически получает фокус при открытии dropdown.


Проблемы поиска при hidden select

Если элемент скрыт через:

display: none;

инициализация может работать некорректно.

Лучше использовать:

visibility: hidden;
position: absolute;

или инициализировать компонент после отображения.


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

Ошибка многих проектов — создание нескольких экземпляров Choices.js.

Плохой вариант:

new Choices('#city');
new Choices('#city');

Правильный подход:

if (!element.dataset.initialized) {
  new Choices(element);

  element.dataset.initialized = 'true';
}

Уничтожение экземпляра

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

choices.destroy();

Удаляются:

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

Это предотвращает:

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

Типичная конфигурация поиска

Практический пример:

const choices = new Choices('#countries', {
  searchEnabled: true,
  searchChoices: true,
  searchFloor: 2,
  searchResultLimit: 15,
  searchFields: [
    'label',
    'value',
    'customProperties.region'
  ],
  shouldSort: false,
  searchPlaceholderValue: 'Поиск страны',
  noResultsText: 'Совпадений нет',
  fuseOptions: {
    threshold: 0.3
  }
});

Такая конфигурация обеспечивает:

  • быстрый поиск;
  • удобный UX;
  • хорошую производительность;
  • поддержку больших наборов данных;
  • гибкую фильтрацию.