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

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

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

Базовая инициализация:

<select id="users">
  <option value="1">Алексей</option>
  <option value="2">Виктор</option>
  <option value="3">Дмитрий</option>
  <option value="4">Екатерина</option>
</select>
new SlimSelect({
  select: '#users'
})

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


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

Для небольших списков поиск может быть избыточным. В таких случаях его отключают через параметр showSearch.

new SlimSelect({
  select: '#users',
  settings: {
    showSearch: false
  }
})

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

  • поле поиска исчезает;
  • выпадающий список становится компактнее;
  • уменьшается количество DOM-элементов.

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

  • выбора пола;
  • переключателей статуса;
  • коротких списков;
  • простых фильтров.

Настройка текста placeholder

По умолчанию внутри поискового поля отображается стандартная подсказка. Её можно изменить.

new SlimSelect({
  select: '#users',
  settings: {
    searchPlaceholder: 'Введите имя пользователя'
  }
})

Результат:

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

Часто используются такие варианты:

searchPlaceholder: 'Поиск...'
searchPlaceholder: 'Найти страну'
searchPlaceholder: 'Введите категорию'

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

Slim Select выполняет поиск без учёта регистра символов.

Пример:

<select id="cities">
  <option>Москва</option>
  <option>Минск</option>
  <option>Алматы</option>
</select>

Запросы:

мос
МОС
Мос

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

Это реализовано внутри библиотеки автоматически и не требует отдельной настройки.


Поиск по частичному совпадению

Slim Select ищет не только полные совпадения, но и части слов.

Пример:

<option>JavaScript</option>
<option>TypeScript</option>
<option>Java</option>

Поисковые запросы:

script
java
type

корректно отфильтруют список.

Такой механизм особенно удобен при работе с:

  • длинными названиями;
  • артикулами;
  • кодами товаров;
  • комбинированными строками.

Минимизация нагрузки при больших списках

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

Использование AJAX-загрузки

Вместо загрузки огромного массива в <select> данные подгружаются динамически.

new SlimSelect({
  select: '#users',
  
  events: {
    search: async (search, currentData) => {
      const response = await fetch('/api/users?q=' + search)
      const data = await response.json()

      return data.map(user => ({
        text: user.name,
        value: user.id
      }))
    }
  }
})

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

  • уменьшается объём DOM;
  • ускоряется открытие списка;
  • сокращается потребление памяти;
  • поиск выполняется на сервере.

Асинхронный поиск

Slim Select поддерживает асинхронную фильтрацию через callback search.

Пример структуры ответа:

[
  {
    text: 'Алексей',
    value: '1'
  },
  {
    text: 'Дмитрий',
    value: '2'
  }
]

Полный пример:

new SlimSelect({
  select: '#users',

  events: {
    search: async (search) => {

      if (search.length < 2) {
        return []
      }

      const response = await fetch(
        `/api/users?query=${search}`
      )

      const users = await response.json()

      return users.map(user => ({
        text: user.name,
        value: user.id
      }))
    }
  }
})

Особенности:

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

Ограничение длины поискового запроса

Иногда необходимо начинать поиск только после ввода определённого количества символов.

new SlimSelect({
  select: '#products',

  events: {
    search: async (search) => {

      if (search.length < 3) {
        return []
      }

      const response = await fetch(
        `/api/products?q=${search}`
      )

      return await response.json()
    }
  }
})

Такой подход:

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

Отображение сообщения при отсутствии результатов

Если поиск ничего не нашёл, библиотека показывает специальное сообщение.

Текст можно изменить:

new SlimSelect({
  select: '#users',

  settings: {
    searchText: 'Ничего не найдено'
  }
})

Применяется для:

  • локализации интерфейса;
  • более понятных сообщений;
  • унификации UI.

Скрытие выбранных элементов из результатов поиска

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

new SlimSelect({
  select: '#skills',

  settings: {
    hideSelected: true
  }
})

Поведение:

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

Комбинирование поиска и multiple select

Наиболее распространённый сценарий — множественный выбор с поиском.

<select id="skills" multiple>
  <option>JavaScript</option>
  <option>TypeScript</option>
  <option>React</option>
  <option>Vue</option>
  <option>Angular</option>
</select>
new SlimSelect({
  select: '#skills',

  settings: {
    searchPlaceholder: 'Поиск технологий',
    hideSelected: true
  }
})

Такой интерфейс используется в:

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

Очистка поискового поля после выбора

По умолчанию Slim Select очищает строку поиска после выбора элемента. Это удобно при:

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

Пользователь получает пустое поле и может сразу вводить новый запрос.


Обработка поисковых событий

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

Пример логирования:

new SlimSelect({
  select: '#users',

  events: {
    search: async (search) => {

      console.log('Поисковый запрос:', search)

      return []
    }
  }
})

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

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

Кастомная фильтрация данных

Slim Select позволяет полностью переопределить логику поиска.

new SlimSelect({
  select: '#products',

  events: {
    search: async (search, currentData) => {

      return currentData.filter(item => {
        return item.text
          .toLowerCase()
          .startsWith(search.toLowerCase())
      })
    }
  }
})

В данном примере:

  • поиск работает только по началу строки;
  • используется startsWith;
  • реализована собственная стратегия фильтрации.

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

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

new SlimSelect({
  select: '#users',

  events: {
    search: async (search, currentData) => {

      return currentData.filter(item => {

        const text = item.text.toLowerCase()
        const value = item.value.toLowerCase()
        const query = search.toLowerCase()

        return (
          text.includes(query) ||
          value.includes(query)
        )
      })
    }
  }
})

Применение:

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

Debounce при поиске

При серверном поиске желательно ограничивать частоту запросов.

Пример debounce:

function debounce(callback, delay) {

  let timeout

  return (...args) => {

    clearTimeout(timeout)

    timeout = setTimeout(() => {
      callback(...args)
    }, delay)
  }
}

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

const searchUsers = debounce(async (search) => {

  const response = await fetch(
    '/api/users?q=' + search
  )

  return await response.json()

}, 300)

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

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

Поиск с группами опций

Slim Select поддерживает <optgroup>.

<select id="frameworks">

  <optgroup label="Frontend">
    <option>React</option>
    <option>Vue</option>
  </optgroup>

  <optgroup label="Backend">
    <option>Node.js</option>
    <option>Laravel</option>
  </optgroup>

</select>

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

Особенности:

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

Локализация поискового интерфейса

Для полноценной русификации обычно настраивают:

new SlimSelect({
  select: '#users',

  settings: {
    searchPlaceholder: 'Поиск...',
    searchText: 'Совпадений не найдено'
  }
})

Это обеспечивает единообразный интерфейс приложения.


Поиск и динамическое обновление данных

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

Пример:

const slim = new SlimSelect({
  select: '#users'
})

slim.setData([
  {
    text: 'Алексей',
    value: '1'
  },
  {
    text: 'Мария',
    value: '2'
  }
])

После вызова setData():

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

Типичные ошибки при настройке поиска

Отключён showSearch

settings: {
  showSearch: false
}

Ошибка приводит к отсутствию поля поиска.


Возврат некорректной структуры данных

Неправильно:

return ['Алексей', 'Мария']

Правильно:

return [
  {
    text: 'Алексей',
    value: '1'
  }
]

Слишком частые запросы к серверу

Проблемный вариант:

search: async (search) => {
  return fetch('/api?q=' + search)
}

Без debounce количество запросов резко возрастает.


Поиск по огромному DOM-списку

<select>
  <!-- 10000 option -->
</select>

Такой подход:

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

Для больших объёмов данных предпочтителен AJAX-поиск.


Практический пример полнофункционального поиска

<select id="employees" multiple></select>
new SlimSelect({
  select: '#employees',

  settings: {
    searchPlaceholder: 'Поиск сотрудников',
    searchText: 'Сотрудники не найдены',
    hideSelected: true
  },

  events: {
    search: async (search) => {

      if (search.length < 2) {
        return []
      }

      const response = await fetch(
        `/api/employees?q=${search}`
      )

      const employees = await response.json()

      return employees.map(employee => ({
        text: employee.name,
        value: employee.id
      }))
    }
  }
})

Возможности данной конфигурации:

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